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-2013, 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/epsimpl.h>   /*I "slepceps.h" I*/
 25: #include <petscdraw.h>

 27: typedef struct {
 28:   PetscErrorCode (*comparison)(PetscScalar,PetscScalar,PetscScalar,PetscScalar,PetscInt*,void*);
 29:   void *comparisonctx;
 30:   ST st;
 31: } EPSSortForSTData;

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

 42:   STBackTransform(data->st,1,&ar,&ai);
 43:   STBackTransform(data->st,1,&br,&bi);
 44:   (*data->comparison)(ar,ai,br,bi,r,data->comparisonctx);
 45:   return(0);
 46: }

 50: /*@
 51:    EPSSolve - Solves the eigensystem.

 53:    Collective on EPS

 55:    Input Parameter:
 56: .  eps - eigensolver context obtained from EPSCreate()

 58:    Options Database Keys:
 59: +  -eps_view - print information about the solver used
 60: .  -eps_view_mat0 binary - save the first matrix (A) to the default binary viewer
 61: .  -eps_view_mat1 binary - save the second matrix (B) to the default binary viewer
 62: -  -eps_plot_eigs - plot computed eigenvalues

 64:    Level: beginner

 66: .seealso: EPSCreate(), EPSSetUp(), EPSDestroy(), EPSSetTolerances()
 67: @*/
 68: PetscErrorCode EPSSolve(EPS eps)
 69: {
 70:   PetscErrorCode    ierr;
 71:   PetscInt          i,nmat;
 72:   PetscReal         re,im;
 73:   PetscScalar       dot;
 74:   PetscBool         flg,isfold,iscayley;
 75:   PetscViewer       viewer;
 76:   PetscViewerFormat format;
 77:   PetscDraw         draw;
 78:   PetscDrawSP       drawsp;
 79:   STMatMode         matmode;
 80:   EPSSortForSTData  data;
 81:   Mat               A,B;
 82:   KSP               ksp;
 83:   Vec               w,x;

 87:   PetscLogEventBegin(EPS_Solve,eps,0,0,0);

 89:   /* call setup */
 90:   EPSSetUp(eps);
 91:   STGetNumMatrices(eps->st,&nmat);
 92:   STGetOperators(eps->st,0,&A);
 93:   if (nmat>1) { STGetOperators(eps->st,1,&B); }
 94:   eps->evecsavailable = PETSC_FALSE;
 95:   eps->nconv = 0;
 96:   eps->its   = 0;
 97:   for (i=0;i<eps->ncv;i++) {
 98:     eps->eigr[i]   = 0.0;
 99:     eps->eigi[i]   = 0.0;
100:     eps->errest[i] = 0.0;
101:   }
102:   EPSMonitor(eps,eps->its,eps->nconv,eps->eigr,eps->eigi,eps->errest,eps->ncv);

104:   PetscObjectTypeCompareAny((PetscObject)eps,&flg,EPSARPACK,EPSBLZPACK,EPSTRLAN,EPSBLOPEX,EPSPRIMME,"");
105:   if (!flg) {
106:     /* temporarily change eigenvalue comparison function */
107:     data.comparison    = eps->comparison;
108:     data.comparisonctx = eps->comparisonctx;
109:     data.st            = eps->st;
110:     eps->comparison    = (eps->which==EPS_ALL)? SlepcCompareLargestMagnitude: EPSSortForSTFunc;
111:     eps->comparisonctx = (eps->which==EPS_ALL)? NULL: &data;
112:   }
113:   DSSetEigenvalueComparison(eps->ds,eps->comparison,eps->comparisonctx);

115:   /* call solver */
116:   (*eps->ops->solve)(eps);

118:   if (!flg) {
119:     /* restore comparison function */
120:     eps->comparison    = data.comparison;
121:     eps->comparisonctx = data.comparisonctx;
122:   }

124:   STGetMatMode(eps->st,&matmode);
125:   if (matmode == ST_MATMODE_INPLACE && eps->ispositive) {
126:     /* Purify eigenvectors before reverting operator */
127:     (*eps->ops->computevectors)(eps);
128:   }
129:   STPostSolve(eps->st);

131:   if (!eps->reason) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_PLIB,"Internal error, solver returned without setting converged reason");

133:   /* Map eigenvalues back to the original problem, necessary in some
134:   * spectral transformations */
135:   if (eps->ops->backtransform) {
136:     (*eps->ops->backtransform)(eps);
137:   }

139:   /* Adjust left eigenvectors in generalized problems: y = B^T y */
140:   if (eps->isgeneralized && eps->leftvecs) {
141:     KSPCreate(PetscObjectComm((PetscObject)eps),&ksp);
142:     KSPSetOperators(ksp,B,B,DIFFERENT_NONZERO_PATTERN);
143:     KSPSetFromOptions(ksp);
144:     MatGetVecs(B,NULL,&w);
145:     for (i=0;i<eps->nconv;i++) {
146:       VecCopy(eps->W[i],w);
147:       KSPSolveTranspose(ksp,w,eps->W[i]);
148:     }
149:     KSPDestroy(&ksp);
150:     VecDestroy(&w);
151:   }

153: #if !defined(PETSC_USE_COMPLEX)
154:   /* reorder conjugate eigenvalues (positive imaginary first) */
155:   for (i=0; i<eps->nconv-1; i++) {
156:     if (eps->eigi[i] != 0) {
157:       if (eps->eigi[i] < 0) {
158:         eps->eigi[i] = -eps->eigi[i];
159:         eps->eigi[i+1] = -eps->eigi[i+1];
160:         if (!eps->evecsavailable) {
161:           /* the next correction only works with eigenvectors */
162:           (*eps->ops->computevectors)(eps);
163:         }
164:         VecScale(eps->V[i+1],-1.0);
165:       }
166:       i++;
167:     }
168:   }
169: #endif

171:   /* quick and dirty solution for FOLD: recompute eigenvalues as Rayleigh quotients */
172:   PetscObjectTypeCompare((PetscObject)eps->st,STFOLD,&isfold);
173:   if (isfold) {
174:     MatGetVecs(A,&w,NULL);
175:     if (!eps->evecsavailable) { (*eps->ops->computevectors)(eps); }
176:     for (i=0;i<eps->nconv;i++) {
177:       x = eps->V[i];
178:       MatMult(A,x,w);
179:       VecDot(w,x,&eps->eigr[i]);
180:       if (eps->isgeneralized) {
181:         MatMult(B,x,w);
182:         VecDot(w,x,&dot);
183:         eps->eigr[i] /= dot;
184:       }
185:     }
186:     VecDestroy(&w);
187:   }

189:   /* In the case of Cayley transform, eigenvectors need to be B-normalized */
190:   PetscObjectTypeCompare((PetscObject)eps->st,STCAYLEY,&iscayley);
191:   if (iscayley && eps->isgeneralized && eps->ishermitian) {
192:     MatGetVecs(B,NULL,&w);
193:     if (!eps->evecsavailable) { (*eps->ops->computevectors)(eps); }
194:     for (i=0;i<eps->nconv;i++) {
195:       x = eps->V[i];
196:       MatMult(B,x,w);
197:       VecDot(w,x,&dot);
198:       VecScale(x,1.0/PetscSqrtScalar(dot));
199:     }
200:     VecDestroy(&w);
201:   }

203:   /* sort eigenvalues according to eps->which parameter */
204:   EPSSortEigenvalues(eps,eps->nconv,eps->eigr,eps->eigi,eps->perm);

206:   PetscLogEventEnd(EPS_Solve,eps,0,0,0);

208:   /* various viewers */
209:   MatViewFromOptions(A,((PetscObject)eps)->prefix,"-eps_view_mat0");
210:   if (nmat>1) { MatViewFromOptions(B,((PetscObject)eps)->prefix,"-eps_view_mat1"); }

212:   PetscOptionsGetViewer(PetscObjectComm((PetscObject)eps),((PetscObject)eps)->prefix,"-eps_view",&viewer,&format,&flg);
213:   if (flg && !PetscPreLoadingOn) {
214:     PetscViewerPushFormat(viewer,format);
215:     EPSView(eps,viewer);
216:     PetscViewerPopFormat(viewer);
217:     PetscViewerDestroy(&viewer);
218:   }

220:   flg = PETSC_FALSE;
221:   PetscOptionsGetBool(((PetscObject)eps)->prefix,"-eps_plot_eigs",&flg,NULL);
222:   if (flg) {
223:     PetscViewerDrawOpen(PETSC_COMM_SELF,0,"Computed Eigenvalues",PETSC_DECIDE,PETSC_DECIDE,300,300,&viewer);
224:     PetscViewerDrawGetDraw(viewer,0,&draw);
225:     PetscDrawSPCreate(draw,1,&drawsp);
226:     for (i=0;i<eps->nconv;i++) {
227: #if defined(PETSC_USE_COMPLEX)
228:       re = PetscRealPart(eps->eigr[i]);
229:       im = PetscImaginaryPart(eps->eigi[i]);
230: #else
231:       re = eps->eigr[i];
232:       im = eps->eigi[i];
233: #endif
234:       PetscDrawSPAddPoint(drawsp,&re,&im);
235:     }
236:     PetscDrawSPDraw(drawsp,PETSC_TRUE);
237:     PetscDrawSPDestroy(&drawsp);
238:     PetscViewerDestroy(&viewer);
239:   }

241:   /* Remove the initial subspaces */
242:   eps->nini = 0;
243:   eps->ninil = 0;
244:   return(0);
245: }

249: /*@
250:    EPSGetIterationNumber - Gets the current iteration number. If the
251:    call to EPSSolve() is complete, then it returns the number of iterations
252:    carried out by the solution method.

254:    Not Collective

256:    Input Parameter:
257: .  eps - the eigensolver context

259:    Output Parameter:
260: .  its - number of iterations

262:    Level: intermediate

264:    Note:
265:    During the i-th iteration this call returns i-1. If EPSSolve() is
266:    complete, then parameter "its" contains either the iteration number at
267:    which convergence was successfully reached, or failure was detected.
268:    Call EPSGetConvergedReason() to determine if the solver converged or
269:    failed and why.

271: .seealso: EPSGetConvergedReason(), EPSSetTolerances()
272: @*/
273: PetscErrorCode EPSGetIterationNumber(EPS eps,PetscInt *its)
274: {
278:   *its = eps->its;
279:   return(0);
280: }

284: /*@
285:    EPSGetOperationCounters - Gets the total number of operator applications,
286:    inner product operations and linear iterations used by the ST object
287:    during the last EPSSolve() call.

289:    Not Collective

291:    Input Parameter:
292: .  eps - EPS context

294:    Output Parameter:
295: +  ops  - number of operator applications
296: .  dots - number of inner product operations
297: -  lits - number of linear iterations

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

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

307:    Level: intermediate

309: @*/
310: PetscErrorCode EPSGetOperationCounters(EPS eps,PetscInt* ops,PetscInt* dots,PetscInt* lits)
311: {

316:   if (!eps->st) { EPSGetST(eps,&eps->st); }
317:   STGetOperationCounters(eps->st,ops,lits);
318:   if (dots) {
319:     if (!eps->ip) { EPSGetIP(eps,&eps->ip); }
320:     IPGetOperationCounters(eps->ip,dots);
321:   }
322:   return(0);
323: }

327: /*@
328:    EPSGetConverged - Gets the number of converged eigenpairs.

330:    Not Collective

332:    Input Parameter:
333: .  eps - the eigensolver context

335:    Output Parameter:
336: .  nconv - number of converged eigenpairs

338:    Note:
339:    This function should be called after EPSSolve() has finished.

341:    Level: beginner

343: .seealso: EPSSetDimensions(), EPSSolve()
344: @*/
345: PetscErrorCode EPSGetConverged(EPS eps,PetscInt *nconv)
346: {
350:   *nconv = eps->nconv;
351:   return(0);
352: }

356: /*@C
357:    EPSGetConvergedReason - Gets the reason why the EPSSolve() iteration was
358:    stopped.

360:    Not Collective

362:    Input Parameter:
363: .  eps - the eigensolver context

365:    Output Parameter:
366: .  reason - negative value indicates diverged, positive value converged

368:    Possible values for reason:
369: +  EPS_CONVERGED_TOL - converged up to tolerance
370: .  EPS_DIVERGED_ITS - required more than its to reach convergence
371: -  EPS_DIVERGED_BREAKDOWN - generic breakdown in method

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

376:    Level: intermediate

378: .seealso: EPSSetTolerances(), EPSSolve(), EPSConvergedReason
379: @*/
380: PetscErrorCode EPSGetConvergedReason(EPS eps,EPSConvergedReason *reason)
381: {
385:   *reason = eps->reason;
386:   return(0);
387: }

391: /*@
392:    EPSGetInvariantSubspace - Gets an orthonormal basis of the computed invariant
393:    subspace.

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

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

400:    Output Parameter:
401: .  v - an array of vectors

403:    Notes:
404:    This function should be called after EPSSolve() has finished.

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

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

416:    Level: intermediate

418: .seealso: EPSGetEigenpair(), EPSGetConverged(), EPSSolve(), EPSGetInvariantSubspaceLeft()
419: @*/
420: PetscErrorCode EPSGetInvariantSubspace(EPS eps,Vec *v)
421: {
423:   PetscInt       i;

429:   if (!eps->V) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
430:   if (!eps->ishermitian && eps->evecsavailable) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"EPSGetInvariantSubspace must be called before EPSGetEigenpair,EPSGetEigenvector,EPSComputeRelativeError or EPSComputeResidualNorm");
431:   if (eps->balance!=EPS_BALANCE_NONE && eps->D) {
432:     for (i=0;i<eps->nconv;i++) {
433:       VecPointwiseDivide(v[i],eps->V[i],eps->D);
434:       VecNormalize(v[i],NULL);
435:     }
436:   } else {
437:     for (i=0;i<eps->nconv;i++) {
438:       VecCopy(eps->V[i],v[i]);
439:     }
440:   }
441:   return(0);
442: }

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

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

452:    Input Parameter:
453: .  eps - the eigensolver context

455:    Output Parameter:
456: .  v - an array of vectors

458:    Notes:
459:    This function should be called after EPSSolve() has finished.

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

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

471:    Level: intermediate

473: .seealso: EPSGetEigenpair(), EPSGetConverged(), EPSSolve(), EPSGetInvariantSubspace
474: @*/
475: PetscErrorCode EPSGetInvariantSubspaceLeft(EPS eps,Vec *v)
476: {
478:   PetscInt       i;

484:   if (!eps->leftvecs) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Must request left vectors with EPSSetLeftVectorsWanted");
485:   if (!eps->W) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
486:   if (!eps->ishermitian && eps->evecsavailable) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"EPSGetInvariantSubspaceLeft must be called before EPSGetEigenpairLeft,EPSComputeRelativeErrorLeft or EPSComputeResidualNormLeft");
487:   for (i=0;i<eps->nconv;i++) {
488:     VecCopy(eps->W[i],v[i]);
489:   }
490:   return(0);
491: }

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

499:    Logically Collective on EPS

501:    Input Parameters:
502: +  eps - eigensolver context
503: -  i   - index of the solution

505:    Output Parameters:
506: +  eigr - real part of eigenvalue
507: .  eigi - imaginary part of eigenvalue
508: .  Vr   - real part of eigenvector
509: -  Vi   - imaginary part of eigenvector

511:    Notes:
512:    If the eigenvalue is real, then eigi and Vi are set to zero. If PETSc is
513:    configured with complex scalars the eigenvalue is stored
514:    directly in eigr (eigi is set to zero) and the eigenvector in Vr (Vi is
515:    set to zero).

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

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

525:    Level: beginner

527: .seealso: EPSGetEigenvalue(), EPSGetEigenvector(), EPSGetEigenvectorLeft(), EPSSolve(),
528:           EPSGetConverged(), EPSSetWhichEigenpairs(), EPSGetInvariantSubspace()
529: @*/
530: PetscErrorCode EPSGetEigenpair(EPS eps,PetscInt i,PetscScalar *eigr,PetscScalar *eigi,Vec Vr,Vec Vi)
531: {

537:   if (!eps->eigr || !eps->eigi || !eps->V) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
538:   if (i<0 || i>=eps->nconv) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
539:   EPSGetEigenvalue(eps,i,eigr,eigi);
540:   if (Vr || Vi) { EPSGetEigenvector(eps,i,Vr,Vi); }
541:   return(0);
542: }

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

549:    Not Collective

551:    Input Parameters:
552: +  eps - eigensolver context
553: -  i   - index of the solution

555:    Output Parameters:
556: +  eigr - real part of eigenvalue
557: -  eigi - imaginary part of eigenvalue

559:    Notes:
560:    If the eigenvalue is real, then eigi is set to zero. If PETSc is
561:    configured with complex scalars the eigenvalue is stored
562:    directly in eigr (eigi is set to zero).

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

568:    Level: beginner

570: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs(),
571:           EPSGetEigenpair()
572: @*/
573: PetscErrorCode EPSGetEigenvalue(EPS eps,PetscInt i,PetscScalar *eigr,PetscScalar *eigi)
574: {
575:   PetscInt       k;

579:   if (!eps->eigr || !eps->eigi) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
580:   if (i<0 || i>=eps->nconv) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
581:   if (!eps->perm) k = i;
582:   else k = eps->perm[i];
583: #if defined(PETSC_USE_COMPLEX)
584:   if (eigr) *eigr = eps->eigr[k];
585:   if (eigi) *eigi = 0;
586: #else
587:   if (eigr) *eigr = eps->eigr[k];
588:   if (eigi) *eigi = eps->eigi[k];
589: #endif
590:   return(0);
591: }

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

598:    Logically Collective on EPS

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

604:    Output Parameters:
605: +  Vr   - real part of eigenvector
606: -  Vi   - imaginary part of eigenvector

608:    Notes:
609:    If the corresponding eigenvalue is real, then Vi is set to zero. If PETSc is
610:    configured with complex scalars the eigenvector is stored
611:    directly in Vr (Vi is set to zero).

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

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

621:    Level: beginner

623: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs(),
624:           EPSGetEigenpair(), EPSGetEigenvectorLeft()
625: @*/
626: PetscErrorCode EPSGetEigenvector(EPS eps,PetscInt i,Vec Vr,Vec Vi)
627: {
629:   PetscInt       k;

637:   if (!eps->V) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
638:   if (i<0 || i>=eps->nconv) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
639:   if (!eps->evecsavailable) {
640:     (*eps->ops->computevectors)(eps);
641:   }
642:   if (!eps->perm) k = i;
643:   else k = eps->perm[i];
644: #if defined(PETSC_USE_COMPLEX)
645:   VecCopy(eps->V[k],Vr);
646:   if (Vi) { VecSet(Vi,0.0); }
647: #else
648:   if (eps->eigi[k] > 0) { /* first value of conjugate pair */
649:     VecCopy(eps->V[k],Vr);
650:     if (Vi) {
651:       VecCopy(eps->V[k+1],Vi);
652:     }
653:   } else if (eps->eigi[k] < 0) { /* second value of conjugate pair */
654:     VecCopy(eps->V[k-1],Vr);
655:     if (Vi) {
656:       VecCopy(eps->V[k],Vi);
657:       VecScale(Vi,-1.0);
658:     }
659:   } else { /* real eigenvalue */
660:     VecCopy(eps->V[k],Vr);
661:     if (Vi) { VecSet(Vi,0.0); }
662:   }
663: #endif
664:   return(0);
665: }

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

673:    Logically Collective on EPS

675:    Input Parameters:
676: +  eps - eigensolver context
677: -  i   - index of the solution

679:    Output Parameters:
680: +  Wr   - real part of eigenvector
681: -  Wi   - imaginary part of eigenvector

683:    Notes:
684:    If the corresponding eigenvalue is real, then Wi is set to zero. If PETSc is
685:    configured with complex scalars the eigenvector is stored
686:    directly in Wr (Wi is set to zero).

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

692:    Level: beginner

694: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs(),
695:           EPSGetEigenpair(), EPSGetEigenvector()
696: @*/
697: PetscErrorCode EPSGetEigenvectorLeft(EPS eps,PetscInt i,Vec Wr,Vec Wi)
698: {
700:   PetscInt       k;

708:   if (!eps->leftvecs) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Must request left vectors with EPSSetLeftVectorsWanted");
709:   if (!eps->W) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
710:   if (i<0 || i>=eps->nconv) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
711:   if (!eps->evecsavailable) {
712:     (*eps->ops->computevectors)(eps);
713:   }
714:   if (!eps->perm) k = i;
715:   else k = eps->perm[i];
716: #if defined(PETSC_USE_COMPLEX)
717:   VecCopy(eps->W[k],Wr);
718:   if (Wi) { VecSet(Wi,0.0); }
719: #else
720:   if (eps->eigi[k] > 0) { /* first value of conjugate pair */
721:     VecCopy(eps->W[k],Wr);
722:     if (Wi) {
723:       VecCopy(eps->W[k+1],Wi);
724:     }
725:   } else if (eps->eigi[k] < 0) { /* second value of conjugate pair */
726:     VecCopy(eps->W[k-1],Wr);
727:     if (Wi) {
728:       VecCopy(eps->W[k],Wi);
729:       VecScale(Wi,-1.0);
730:     }
731:   } else { /* real eigenvalue */
732:     VecCopy(eps->W[k],Wr);
733:     if (Wi) { VecSet(Wi,0.0); }
734:   }
735: #endif
736:   return(0);
737: }

741: /*@
742:    EPSGetErrorEstimate - Returns the error estimate associated to the i-th
743:    computed eigenpair.

745:    Not Collective

747:    Input Parameter:
748: +  eps - eigensolver context
749: -  i   - index of eigenpair

751:    Output Parameter:
752: .  errest - the error estimate

754:    Notes:
755:    This is the error estimate used internally by the eigensolver. The actual
756:    error bound can be computed with EPSComputeRelativeError(). See also the users
757:    manual for details.

759:    Level: advanced

761: .seealso: EPSComputeRelativeError()
762: @*/
763: PetscErrorCode EPSGetErrorEstimate(EPS eps,PetscInt i,PetscReal *errest)
764: {
768:   if (!eps->eigr || !eps->eigi) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
769:   if (i<0 || i>=eps->nconv) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
770:   if (eps->perm) i = eps->perm[i];
771:   if (errest) *errest = eps->errest[i];
772:   return(0);
773: }

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

781:    Not Collective

783:    Input Parameter:
784: +  eps - eigensolver context
785: -  i   - index of eigenpair

787:    Output Parameter:
788: .  errest - the left error estimate

790:    Notes:
791:    This is the error estimate used internally by the eigensolver. The actual
792:    error bound can be computed with EPSComputeRelativeErrorLeft(). See also the users
793:    manual for details.

795:    Level: advanced

797: .seealso: EPSComputeRelativeErrorLeft()
798: @*/
799: PetscErrorCode EPSGetErrorEstimateLeft(EPS eps,PetscInt i,PetscReal *errest)
800: {
804:   if (!eps->eigr || !eps->eigi) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"EPSSolve must be called first");
805:   if (!eps->leftvecs) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Must request left vectors with EPSSetLeftVectorsWanted");
806:   if (i<0 || i>=eps->nconv) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
807:   if (eps->perm) i = eps->perm[i];
808:   if (errest) *errest = eps->errest_left[i];
809:   return(0);
810: }

814: /*
815:    EPSComputeResidualNorm_Private - Computes the norm of the residual vector
816:    associated with an eigenpair.
817: */
818: PetscErrorCode EPSComputeResidualNorm_Private(EPS eps,PetscScalar kr,PetscScalar ki,Vec xr,Vec xi,PetscReal *norm)
819: {
821:   PetscInt       nmat;
822:   Vec            u,w;
823:   Mat            A,B;
824: #if !defined(PETSC_USE_COMPLEX)
825:   Vec            v;
826:   PetscReal      ni,nr;
827: #endif

830:   STGetNumMatrices(eps->st,&nmat);
831:   STGetOperators(eps->st,0,&A);
832:   if (nmat>1) { STGetOperators(eps->st,1,&B); }
833:   VecDuplicate(eps->V[0],&u);
834:   VecDuplicate(eps->V[0],&w);

836: #if !defined(PETSC_USE_COMPLEX)
837:   if (ki == 0 || PetscAbsScalar(ki) < PetscAbsScalar(kr*PETSC_MACHINE_EPSILON)) {
838: #endif
839:     MatMult(A,xr,u);                             /* u=A*x */
840:     if (PetscAbsScalar(kr) > PETSC_MACHINE_EPSILON) {
841:       if (eps->isgeneralized) { MatMult(B,xr,w); }
842:       else { VecCopy(xr,w); }                    /* w=B*x */
843:       VecAXPY(u,-kr,w);                          /* u=A*x-k*B*x */
844:     }
845:     VecNorm(u,NORM_2,norm);
846: #if !defined(PETSC_USE_COMPLEX)
847:   } else {
848:     VecDuplicate(eps->V[0],&v);
849:     MatMult(A,xr,u);                             /* u=A*xr */
850:     if (SlepcAbsEigenvalue(kr,ki) > PETSC_MACHINE_EPSILON) {
851:       if (eps->isgeneralized) { MatMult(B,xr,v); }
852:       else { VecCopy(xr,v); }                    /* v=B*xr */
853:       VecAXPY(u,-kr,v);                          /* u=A*xr-kr*B*xr */
854:       if (eps->isgeneralized) { MatMult(B,xi,w); }
855:       else { VecCopy(xi,w); }                    /* w=B*xi */
856:       VecAXPY(u,ki,w);                           /* u=A*xr-kr*B*xr+ki*B*xi */
857:     }
858:     VecNorm(u,NORM_2,&nr);
859:     MatMult(A,xi,u);                             /* u=A*xi */
860:     if (SlepcAbsEigenvalue(kr,ki) > PETSC_MACHINE_EPSILON) {
861:       VecAXPY(u,-kr,w);                          /* u=A*xi-kr*B*xi */
862:       VecAXPY(u,-ki,v);                          /* u=A*xi-kr*B*xi-ki*B*xr */
863:     }
864:     VecNorm(u,NORM_2,&ni);
865:     *norm = SlepcAbsEigenvalue(nr,ni);
866:     VecDestroy(&v);
867:   }
868: #endif

870:   VecDestroy(&w);
871:   VecDestroy(&u);
872:   return(0);
873: }

877: /*@
878:    EPSComputeResidualNorm - Computes the norm of the residual vector associated with
879:    the i-th computed eigenpair.

881:    Collective on EPS

883:    Input Parameter:
884: +  eps - the eigensolver context
885: -  i   - the solution index

887:    Output Parameter:
888: .  norm - the residual norm, computed as ||Ax-kBx||_2 where k is the
889:    eigenvalue and x is the eigenvector.
890:    If k=0 then the residual norm is computed as ||Ax||_2.

892:    Notes:
893:    The index i should be a value between 0 and nconv-1 (see EPSGetConverged()).
894:    Eigenpairs are indexed according to the ordering criterion established
895:    with EPSSetWhichEigenpairs().

897:    Level: beginner

899: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs()
900: @*/
901: PetscErrorCode EPSComputeResidualNorm(EPS eps,PetscInt i,PetscReal *norm)
902: {
904:   Vec            xr,xi;
905:   PetscScalar    kr,ki;

911:   VecDuplicate(eps->V[0],&xr);
912:   VecDuplicate(eps->V[0],&xi);
913:   EPSGetEigenpair(eps,i,&kr,&ki,xr,xi);
914:   EPSComputeResidualNorm_Private(eps,kr,ki,xr,xi,norm);
915:   VecDestroy(&xr);
916:   VecDestroy(&xi);
917:   return(0);
918: }

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

926:    Collective on EPS

928:    Input Parameter:
929: +  eps - the eigensolver context
930: -  i   - the solution index

932:    Output Parameter:
933: .  norm - the residual norm, computed as ||y'A-ky'B||_2 where k is the
934:    eigenvalue and y is the left eigenvector.
935:    If k=0 then the residual norm is computed as ||y'A||_2.

937:    Notes:
938:    The index i should be a value between 0 and nconv-1 (see EPSGetConverged()).
939:    Eigenpairs are indexed according to the ordering criterion established
940:    with EPSSetWhichEigenpairs().

942:    Level: beginner

944: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs()
945: @*/
946: PetscErrorCode EPSComputeResidualNormLeft(EPS eps,PetscInt i,PetscReal *norm)
947: {
949:   Vec            u,v,w,xr,xi;
950:   Mat            A,B;
951:   PetscInt       nmat;
952:   PetscScalar    kr,ki;
953: #if !defined(PETSC_USE_COMPLEX)
954:   PetscReal      ni,nr;
955: #endif

961:   if (!eps->leftvecs) SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Must request left vectors with EPSSetLeftVectorsWanted");
962:   STGetNumMatrices(eps->st,&nmat);
963:   STGetOperators(eps->st,0,&A);
964:   if (nmat>1) { STGetOperators(eps->st,1,&B); }
965:   VecDuplicate(eps->W[0],&u);
966:   VecDuplicate(eps->W[0],&v);
967:   VecDuplicate(eps->W[0],&w);
968:   VecDuplicate(eps->W[0],&xr);
969:   VecDuplicate(eps->W[0],&xi);
970:   EPSGetEigenvalue(eps,i,&kr,&ki);
971:   EPSGetEigenvectorLeft(eps,i,xr,xi);

973: #if !defined(PETSC_USE_COMPLEX)
974:   if (ki == 0 ||
975:     PetscAbsScalar(ki) < PetscAbsScalar(kr*PETSC_MACHINE_EPSILON)) {
976: #endif
977:     MatMultTranspose(A,xr,u); /* u=A'*x */
978:     if (PetscAbsScalar(kr) > PETSC_MACHINE_EPSILON) {
979:       if (eps->isgeneralized) { MatMultTranspose(B,xr,w); }
980:       else { VecCopy(xr,w); } /* w=B'*x */
981:       VecAXPY(u,-kr,w); /* u=A'*x-k*B'*x */
982:     }
983:     VecNorm(u,NORM_2,norm);
984: #if !defined(PETSC_USE_COMPLEX)
985:   } else {
986:     MatMultTranspose(A,xr,u); /* u=A'*xr */
987:     if (eps->isgeneralized) { MatMultTranspose(B,xr,v); }
988:     else { VecCopy(xr,v); } /* v=B'*xr */
989:     VecAXPY(u,-kr,v); /* u=A'*xr-kr*B'*xr */
990:     if (eps->isgeneralized) { MatMultTranspose(B,xi,w); }
991:     else { VecCopy(xi,w); } /* w=B'*xi */
992:     VecAXPY(u,ki,w); /* u=A'*xr-kr*B'*xr+ki*B'*xi */
993:     VecNorm(u,NORM_2,&nr);
994:     MatMultTranspose(A,xi,u); /* u=A'*xi */
995:     VecAXPY(u,-kr,w); /* u=A'*xi-kr*B'*xi */
996:     VecAXPY(u,-ki,v); /* u=A'*xi-kr*B'*xi-ki*B'*xr */
997:     VecNorm(u,NORM_2,&ni);
998:     *norm = SlepcAbsEigenvalue(nr,ni);
999:   }
1000: #endif

1002:   VecDestroy(&w);
1003:   VecDestroy(&v);
1004:   VecDestroy(&u);
1005:   VecDestroy(&xr);
1006:   VecDestroy(&xi);
1007:   return(0);
1008: }

1012: /*
1013:    EPSComputeRelativeError_Private - Computes the relative error bound
1014:    associated with an eigenpair.
1015: */
1016: PetscErrorCode EPSComputeRelativeError_Private(EPS eps,PetscScalar kr,PetscScalar ki,Vec xr,Vec xi,PetscReal *error)
1017: {
1019:   PetscReal      norm,er;
1020: #if !defined(PETSC_USE_COMPLEX)
1021:   PetscReal      ei;
1022: #endif

1025:   EPSComputeResidualNorm_Private(eps,kr,ki,xr,xi,&norm);

1027: #if !defined(PETSC_USE_COMPLEX)
1028:   if (ki == 0) {
1029: #endif
1030:     VecNorm(xr,NORM_2,&er);
1031: #if !defined(PETSC_USE_COMPLEX)
1032:   } else {
1033:     VecNorm(xr,NORM_2,&er);
1034:     VecNorm(xi,NORM_2,&ei);
1035:     er = SlepcAbsEigenvalue(er,ei);
1036:   }
1037: #endif
1038:   (*eps->converged)(eps,kr,ki,norm/er,error,eps->convergedctx);
1039:   return(0);
1040: }

1044: /*@
1045:    EPSComputeRelativeError - Computes the relative error bound associated
1046:    with the i-th computed eigenpair.

1048:    Collective on EPS

1050:    Input Parameter:
1051: +  eps - the eigensolver context
1052: -  i   - the solution index

1054:    Output Parameter:
1055: .  error - the relative error bound, computed as ||Ax-kBx||_2/||kx||_2 where
1056:    k is the eigenvalue and x is the eigenvector.
1057:    If k=0 the relative error is computed as ||Ax||_2/||x||_2.

1059:    Level: beginner

1061: .seealso: EPSSolve(), EPSComputeResidualNorm(), EPSGetErrorEstimate()
1062: @*/
1063: PetscErrorCode EPSComputeRelativeError(EPS eps,PetscInt i,PetscReal *error)
1064: {
1066:   Vec            xr,xi;
1067:   PetscScalar    kr,ki;

1073:   VecDuplicate(eps->V[0],&xr);
1074:   VecDuplicate(eps->V[0],&xi);
1075:   EPSGetEigenpair(eps,i,&kr,&ki,xr,xi);
1076:   EPSComputeRelativeError_Private(eps,kr,ki,xr,xi,error);
1077:   VecDestroy(&xr);
1078:   VecDestroy(&xi);
1079:   return(0);
1080: }

1084: /*@
1085:    EPSComputeRelativeErrorLeft - Computes the relative error bound associated
1086:    with the i-th computed eigenvalue and left eigenvector (only available in
1087:    two-sided eigensolvers).

1089:    Collective on EPS

1091:    Input Parameter:
1092: +  eps - the eigensolver context
1093: -  i   - the solution index

1095:    Output Parameter:
1096: .  error - the relative error bound, computed as ||y'A-ky'B||_2/||ky||_2 where
1097:    k is the eigenvalue and y is the left eigenvector.
1098:    If k=0 the relative error is computed as ||y'A||_2/||y||_2.

1100:    Level: beginner

1102: .seealso: EPSSolve(), EPSComputeResidualNormLeft(), EPSGetErrorEstimateLeft()
1103: @*/
1104: PetscErrorCode EPSComputeRelativeErrorLeft(EPS eps,PetscInt i,PetscReal *error)
1105: {
1107:   Vec            xr,xi;
1108:   PetscScalar    kr,ki;
1109:   PetscReal      norm,er;
1110: #if !defined(PETSC_USE_COMPLEX)
1111:   Vec            u;
1112:   PetscReal      ei;
1113: #endif

1117:   EPSComputeResidualNormLeft(eps,i,&norm);
1120:   VecDuplicate(eps->W[0],&xr);
1121:   VecDuplicate(eps->W[0],&xi);
1122:   EPSGetEigenvalue(eps,i,&kr,&ki);
1123:   EPSGetEigenvectorLeft(eps,i,xr,xi);

1125: #if !defined(PETSC_USE_COMPLEX)
1126:   if (ki == 0 || PetscAbsScalar(ki) < PetscAbsScalar(kr*PETSC_MACHINE_EPSILON)) {
1127: #endif
1128:     VecNorm(xr,NORM_2,&er);
1129:     if (PetscAbsScalar(kr) > PETSC_MACHINE_EPSILON) *error = norm/(PetscAbsScalar(kr)*er);
1130:     else *error = norm / er;
1131: #if !defined(PETSC_USE_COMPLEX)
1132:   } else {
1133:     VecDuplicate(xi,&u);
1134:     VecCopy(xi,u);
1135:     VecAXPBY(u,kr,-ki,xr);
1136:     VecNorm(u,NORM_2,&er);
1137:     VecAXPBY(xi,kr,ki,xr);
1138:     VecNorm(xi,NORM_2,&ei);
1139:     VecDestroy(&u);
1140:     *error = norm / SlepcAbsEigenvalue(er,ei);
1141:   }
1142: #endif

1144:   VecDestroy(&xr);
1145:   VecDestroy(&xi);
1146:   return(0);
1147: }

1151: /*@
1152:    EPSSortEigenvalues - Sorts a list of eigenvalues according to the criterion
1153:    specified via EPSSetWhichEigenpairs().

1155:    Not Collective

1157:    Input Parameters:
1158: +  eps   - the eigensolver context
1159: .  n     - number of eigenvalues in the list
1160: .  eigr  - pointer to the array containing the eigenvalues
1161: -  eigi  - imaginary part of the eigenvalues (only when using real numbers)

1163:    Output Parameter:
1164: .  perm  - resulting permutation

1166:    Note:
1167:    The result is a list of indices in the original eigenvalue array
1168:    corresponding to the first nev eigenvalues sorted in the specified
1169:    criterion.

1171:    Level: developer

1173: .seealso: EPSSetWhichEigenpairs()
1174: @*/
1175: PetscErrorCode EPSSortEigenvalues(EPS eps,PetscInt n,PetscScalar *eigr,PetscScalar *eigi,PetscInt *perm)
1176: {
1178:   PetscScalar    re,im;
1179:   PetscInt       i,j,result,tmp;

1186:   for (i=0; i<n; i++) { perm[i] = i; }
1187:   /* insertion sort */
1188:   for (i=n-1; i>=0; i--) {
1189:     re = eigr[perm[i]];
1190:     im = eigi[perm[i]];
1191:     j = i + 1;
1192: #if !defined(PETSC_USE_COMPLEX)
1193:     if (im != 0) {
1194:       /* complex eigenvalue */
1195:       i--;
1196:       im = eigi[perm[i]];
1197:     }
1198: #endif
1199:     while (j<n) {
1200:       EPSCompareEigenvalues(eps,re,im,eigr[perm[j]],eigi[perm[j]],&result);
1201:       if (result < 0) break;
1202: #if !defined(PETSC_USE_COMPLEX)
1203:       /* keep together every complex conjugated eigenpair */
1204:       if (im == 0) {
1205:         if (eigi[perm[j]] == 0) {
1206: #endif
1207:           tmp = perm[j-1]; perm[j-1] = perm[j]; perm[j] = tmp;
1208:           j++;
1209: #if !defined(PETSC_USE_COMPLEX)
1210:         } else {
1211:           tmp = perm[j-1]; perm[j-1] = perm[j]; perm[j] = perm[j+1]; perm[j+1] = tmp;
1212:           j+=2;
1213:         }
1214:       } else {
1215:         if (eigi[perm[j]] == 0) {
1216:           tmp = perm[j-2]; perm[j-2] = perm[j]; perm[j] = perm[j-1]; perm[j-1] = tmp;
1217:           j++;
1218:         } else {
1219:           tmp = perm[j-2]; perm[j-2] = perm[j]; perm[j] = tmp;
1220:           tmp = perm[j-1]; perm[j-1] = perm[j+1]; perm[j+1] = tmp;
1221:           j+=2;
1222:         }
1223:       }
1224: #endif
1225:     }
1226:   }
1227:   return(0);
1228: }

1232: /*@
1233:    EPSCompareEigenvalues - Compares two (possibly complex) eigenvalues according
1234:    to a certain criterion.

1236:    Not Collective

1238:    Input Parameters:
1239: +  eps   - the eigensolver context
1240: .  ar     - real part of the 1st eigenvalue
1241: .  ai     - imaginary part of the 1st eigenvalue
1242: .  br     - real part of the 2nd eigenvalue
1243: -  bi     - imaginary part of the 2nd eigenvalue

1245:    Output Parameter:
1246: .  res    - result of comparison

1248:    Notes:
1249:    The returning parameter 'res' can be:
1250: +  negative - if the 1st eigenvalue is preferred to the 2st one
1251: .  zero     - if both eigenvalues are equally preferred
1252: -  positive - if the 2st eigenvalue is preferred to the 1st one

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

1257:    Level: developer

1259: .seealso: EPSSortEigenvalues(), EPSSetWhichEigenpairs()
1260: @*/
1261: PetscErrorCode EPSCompareEigenvalues(EPS eps,PetscScalar ar,PetscScalar ai,PetscScalar br,PetscScalar bi,PetscInt *result)
1262: {

1268:   if (!eps->comparison) SETERRQ(PETSC_COMM_SELF,1,"Undefined eigenvalue comparison function");
1269:   (*eps->comparison)(ar,ai,br,bi,result,eps->comparisonctx);
1270:   return(0);
1271: }

1275: /*@
1276:    EPSGetStartVector - Gets a suitable vector to be used as the starting vector
1277:    for the recurrence that builds the right subspace.

1279:    Collective on EPS and Vec

1281:    Input Parameters:
1282: +  eps - the eigensolver context
1283: -  i   - iteration number

1285:    Output Parameters:
1286: +  vec - the start vector
1287: -  breakdown - flag indicating that a breakdown has occurred

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

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

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

1303:    Level: developer

1305: .seealso: EPSSetInitialSpace()
1306: @*/
1307: PetscErrorCode EPSGetStartVector(EPS eps,PetscInt i,Vec vec,PetscBool *breakdown)
1308: {
1310:   PetscReal      norm;
1311:   PetscBool      lindep;
1312:   Vec            w;


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

1322:   /* For the first step, use the first initial vector, otherwise a random one */
1323:   if (i==0 && eps->nini>0) {
1324:     VecCopy(eps->V[0],w);
1325:   } else {
1326:     SlepcVecSetRandom(w,eps->rand);
1327:   }

1329:   /* Force the vector to be in the range of OP for definite generalized problems */
1330:   if (eps->ispositive || (eps->isgeneralized && eps->ishermitian)) {
1331:     STApply(eps->st,w,vec);
1332:   } else {
1333:     VecCopy(w,vec);
1334:   }

1336:   /* Orthonormalize the vector with respect to previous vectors */
1337:   IPOrthogonalize(eps->ip,eps->nds,eps->defl,i,NULL,eps->V,vec,NULL,&norm,&lindep);
1338:   if (breakdown) *breakdown = lindep;
1339:   else if (lindep || norm == 0.0) {
1340:     if (i==0) SETERRQ(PetscObjectComm((PetscObject)eps),1,"Initial vector is zero or belongs to the deflation space");
1341:     else SETERRQ(PetscObjectComm((PetscObject)eps),1,"Unable to generate more start vectors");
1342:   }
1343:   VecScale(vec,1.0/norm);

1345:   VecDestroy(&w);
1346:   return(0);
1347: }

1351: /*@
1352:    EPSGetStartVectorLeft - Gets a suitable vector to be used as the starting vector
1353:    in the recurrence that builds the left subspace (in methods that work with two
1354:    subspaces).

1356:    Collective on EPS and Vec

1358:    Input Parameters:
1359: +  eps - the eigensolver context
1360: -  i   - iteration number

1362:    Output Parameter:
1363: +  vec - the start vector
1364: -  breakdown - flag indicating that a breakdown has occurred

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

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

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

1378:    Level: developer

1380: .seealso: EPSSetInitialSpaceLeft()
1381: @*/
1382: PetscErrorCode EPSGetStartVectorLeft(EPS eps,PetscInt i,Vec vec,PetscBool *breakdown)
1383: {
1385:   PetscReal      norm;
1386:   PetscBool      lindep;
1387:   Vec            w;


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

1397:   /* For the first step, use the first initial left vector, otherwise a random one */
1398:   if (i==0 && eps->ninil>0) {
1399:     VecCopy(eps->W[0],w);
1400:   } else {
1401:     SlepcVecSetRandom(w,eps->rand);
1402:   }

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

1407:   /* Orthonormalize the vector with respect to previous vectors */
1408:   IPOrthogonalize(eps->ip,0,NULL,i,NULL,eps->W,vec,NULL,&norm,&lindep);
1409:   if (breakdown) *breakdown = lindep;
1410:   else if (lindep || norm == 0.0) {
1411:     if (i==0) SETERRQ(PetscObjectComm((PetscObject)eps),1,"Left initial vector is zero");
1412:     else SETERRQ(PetscObjectComm((PetscObject)eps),1,"Unable to generate more left start vectors");
1413:   }
1414:   VecScale(vec,1/norm);

1416:   VecDestroy(&w);
1417:   return(0);
1418: }