Actual source code: epssolve.c

slepc-3.19.0 2023-03-31
Report Typos and Errors
  1: /*
  2:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  3:    SLEPc - Scalable Library for Eigenvalue Problem Computations
  4:    Copyright (c) 2002-, Universitat Politecnica de Valencia, Spain

  6:    This file is part of SLEPc.
  7:    SLEPc is distributed under a 2-clause BSD license (see LICENSE).
  8:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  9: */
 10: /*
 11:    EPS routines related to the solution process
 12: */

 14: #include <slepc/private/epsimpl.h>
 15: #include <slepc/private/bvimpl.h>
 16: #include <petscdraw.h>

 18: PetscErrorCode EPSComputeVectors(EPS eps)
 19: {
 20:   PetscFunctionBegin;
 21:   EPSCheckSolved(eps,1);
 22:   if (eps->state==EPS_STATE_SOLVED) PetscTryTypeMethod(eps,computevectors);
 23:   eps->state = EPS_STATE_EIGENVECTORS;
 24:   PetscFunctionReturn(PETSC_SUCCESS);
 25: }

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

 29: static PetscErrorCode EPSComputeValues(EPS eps)
 30: {
 31:   PetscBool      injective,iscomp,isfilter;
 32:   PetscInt       i,n,aux,nconv0;
 33:   Mat            A,B=NULL,G,Z;

 35:   PetscFunctionBegin;
 36:   switch (eps->categ) {
 37:     case EPS_CATEGORY_KRYLOV:
 38:     case EPS_CATEGORY_OTHER:
 39:       PetscCall(STIsInjective(eps->st,&injective));
 40:       if (injective) {
 41:         /* one-to-one mapping: backtransform eigenvalues */
 42:         PetscUseTypeMethod(eps,backtransform);
 43:       } else {
 44:         /* compute eigenvalues from Rayleigh quotient */
 45:         PetscCall(DSGetDimensions(eps->ds,&n,NULL,NULL,NULL));
 46:         if (!n) break;
 47:         PetscCall(EPSGetOperators(eps,&A,&B));
 48:         PetscCall(BVSetActiveColumns(eps->V,0,n));
 49:         PetscCall(DSGetCompact(eps->ds,&iscomp));
 50:         PetscCall(DSSetCompact(eps->ds,PETSC_FALSE));
 51:         PetscCall(DSGetMat(eps->ds,DS_MAT_A,&G));
 52:         PetscCall(BVMatProject(eps->V,A,eps->V,G));
 53:         PetscCall(DSRestoreMat(eps->ds,DS_MAT_A,&G));
 54:         if (B) {
 55:           PetscCall(DSGetMat(eps->ds,DS_MAT_B,&G));
 56:           PetscCall(BVMatProject(eps->V,B,eps->V,G));
 57:           PetscCall(DSRestoreMat(eps->ds,DS_MAT_A,&G));
 58:         }
 59:         PetscCall(DSSolve(eps->ds,eps->eigr,eps->eigi));
 60:         PetscCall(DSSort(eps->ds,eps->eigr,eps->eigi,NULL,NULL,NULL));
 61:         PetscCall(DSSynchronize(eps->ds,eps->eigr,eps->eigi));
 62:         PetscCall(DSSetCompact(eps->ds,iscomp));
 63:         if (eps->ishermitian && (!eps->isgeneralized || eps->ispositive)) { /* V = V * Z */
 64:           PetscCall(DSVectors(eps->ds,DS_MAT_X,NULL,NULL));
 65:           PetscCall(DSGetMat(eps->ds,DS_MAT_X,&Z));
 66:           PetscCall(BVMultInPlace(eps->V,Z,0,n));
 67:           PetscCall(DSRestoreMat(eps->ds,DS_MAT_X,&Z));
 68:         }
 69:         /* in case of STFILTER discard computed eigenvalues that lie outside the wanted interval */
 70:         PetscCall(PetscObjectTypeCompare((PetscObject)eps->st,STFILTER,&isfilter));
 71:         if (isfilter) {
 72:           nconv0 = eps->nconv;
 73:           for (i=0;i<eps->nconv;i++) {
 74:             if (PetscRealPart(eps->eigr[eps->perm[i]])<eps->inta || PetscRealPart(eps->eigr[eps->perm[i]])>eps->intb) {
 75:               eps->nconv--;
 76:               if (i<eps->nconv) { SWAP(eps->perm[i],eps->perm[eps->nconv],aux); i--; }
 77:             }
 78:           }
 79:           if (nconv0>eps->nconv) PetscCall(PetscInfo(eps,"Discarded %" PetscInt_FMT " computed eigenvalues lying outside the interval\n",nconv0-eps->nconv));
 80:         }
 81:       }
 82:       break;
 83:     case EPS_CATEGORY_PRECOND:
 84:     case EPS_CATEGORY_CONTOUR:
 85:       /* eigenvalues already available as an output of the solver */
 86:       break;
 87:   }
 88:   PetscFunctionReturn(PETSC_SUCCESS);
 89: }

 91: /*@
 92:    EPSSolve - Solves the eigensystem.

 94:    Collective

 96:    Input Parameter:
 97: .  eps - eigensolver context obtained from EPSCreate()

 99:    Options Database Keys:
100: +  -eps_view - print information about the solver used
101: .  -eps_view_mat0 - view the first matrix (A)
102: .  -eps_view_mat1 - view the second matrix (B)
103: .  -eps_view_vectors - view the computed eigenvectors
104: .  -eps_view_values - view the computed eigenvalues
105: .  -eps_converged_reason - print reason for convergence, and number of iterations
106: .  -eps_error_absolute - print absolute errors of each eigenpair
107: .  -eps_error_relative - print relative errors of each eigenpair
108: -  -eps_error_backward - print backward errors of each eigenpair

110:    Notes:
111:    All the command-line options listed above admit an optional argument specifying
112:    the viewer type and options. For instance, use '-eps_view_mat0 binary:amatrix.bin'
113:    to save the A matrix to a binary file, '-eps_view_values draw' to draw the computed
114:    eigenvalues graphically, or '-eps_error_relative :myerr.m:ascii_matlab' to save
115:    the errors in a file that can be executed in Matlab.

117:    Level: beginner

119: .seealso: EPSCreate(), EPSSetUp(), EPSDestroy(), EPSSetTolerances()
120: @*/
121: PetscErrorCode EPSSolve(EPS eps)
122: {
123:   PetscInt       i;
124:   STMatMode      matmode;
125:   Mat            A,B;

127:   PetscFunctionBegin;
129:   if (eps->state>=EPS_STATE_SOLVED) PetscFunctionReturn(PETSC_SUCCESS);
130:   PetscCall(PetscLogEventBegin(EPS_Solve,eps,0,0,0));

132:   /* Call setup */
133:   PetscCall(EPSSetUp(eps));
134:   eps->nconv = 0;
135:   eps->its   = 0;
136:   for (i=0;i<eps->ncv;i++) {
137:     eps->eigr[i]   = 0.0;
138:     eps->eigi[i]   = 0.0;
139:     eps->errest[i] = 0.0;
140:     eps->perm[i]   = i;
141:   }
142:   PetscCall(EPSViewFromOptions(eps,NULL,"-eps_view_pre"));
143:   PetscCall(RGViewFromOptions(eps->rg,NULL,"-rg_view"));

145:   /* Call solver */
146:   PetscUseTypeMethod(eps,solve);
147:   PetscCheck(eps->reason,PetscObjectComm((PetscObject)eps),PETSC_ERR_PLIB,"Internal error, solver returned without setting converged reason");
148:   eps->state = EPS_STATE_SOLVED;

150:   /* Only the first nconv columns contain useful information (except in CISS) */
151:   PetscCall(BVSetActiveColumns(eps->V,0,eps->nconv));
152:   if (eps->twosided) PetscCall(BVSetActiveColumns(eps->W,0,eps->nconv));

154:   /* If inplace, purify eigenvectors before reverting operator */
155:   PetscCall(STGetMatMode(eps->st,&matmode));
156:   if (matmode == ST_MATMODE_INPLACE && eps->ispositive) PetscCall(EPSComputeVectors(eps));
157:   PetscCall(STPostSolve(eps->st));

159:   /* Map eigenvalues back to the original problem if appropriate */
160:   PetscCall(EPSComputeValues(eps));

162: #if !defined(PETSC_USE_COMPLEX)
163:   /* Reorder conjugate eigenvalues (positive imaginary first) */
164:   for (i=0;i<eps->nconv-1;i++) {
165:     if (eps->eigi[i] != 0) {
166:       if (eps->eigi[i] < 0) {
167:         eps->eigi[i] = -eps->eigi[i];
168:         eps->eigi[i+1] = -eps->eigi[i+1];
169:         /* the next correction only works with eigenvectors */
170:         PetscCall(EPSComputeVectors(eps));
171:         PetscCall(BVScaleColumn(eps->V,i+1,-1.0));
172:       }
173:       i++;
174:     }
175:   }
176: #endif

178:   /* Sort eigenvalues according to eps->which parameter */
179:   PetscCall(SlepcSortEigenvalues(eps->sc,eps->nconv,eps->eigr,eps->eigi,eps->perm));
180:   PetscCall(PetscLogEventEnd(EPS_Solve,eps,0,0,0));

182:   /* Various viewers */
183:   PetscCall(EPSViewFromOptions(eps,NULL,"-eps_view"));
184:   PetscCall(EPSConvergedReasonViewFromOptions(eps));
185:   PetscCall(EPSErrorViewFromOptions(eps));
186:   PetscCall(EPSValuesViewFromOptions(eps));
187:   PetscCall(EPSVectorsViewFromOptions(eps));
188:   PetscCall(EPSGetOperators(eps,&A,&B));
189:   PetscCall(MatViewFromOptions(A,(PetscObject)eps,"-eps_view_mat0"));
190:   if (eps->isgeneralized) PetscCall(MatViewFromOptions(B,(PetscObject)eps,"-eps_view_mat1"));

192:   /* Remove deflation and initial subspaces */
193:   if (eps->nds) {
194:     PetscCall(BVSetNumConstraints(eps->V,0));
195:     eps->nds = 0;
196:   }
197:   eps->nini = 0;
198:   PetscFunctionReturn(PETSC_SUCCESS);
199: }

201: /*@
202:    EPSGetIterationNumber - Gets the current iteration number. If the
203:    call to EPSSolve() is complete, then it returns the number of iterations
204:    carried out by the solution method.

206:    Not Collective

208:    Input Parameter:
209: .  eps - the eigensolver context

211:    Output Parameter:
212: .  its - number of iterations

214:    Note:
215:    During the i-th iteration this call returns i-1. If EPSSolve() is
216:    complete, then parameter "its" contains either the iteration number at
217:    which convergence was successfully reached, or failure was detected.
218:    Call EPSGetConvergedReason() to determine if the solver converged or
219:    failed and why.

221:    Level: intermediate

223: .seealso: EPSGetConvergedReason(), EPSSetTolerances()
224: @*/
225: PetscErrorCode EPSGetIterationNumber(EPS eps,PetscInt *its)
226: {
227:   PetscFunctionBegin;
230:   *its = eps->its;
231:   PetscFunctionReturn(PETSC_SUCCESS);
232: }

234: /*@
235:    EPSGetConverged - Gets the number of converged eigenpairs.

237:    Not Collective

239:    Input Parameter:
240: .  eps - the eigensolver context

242:    Output Parameter:
243: .  nconv - number of converged eigenpairs

245:    Note:
246:    This function should be called after EPSSolve() has finished.

248:    Level: beginner

250: .seealso: EPSSetDimensions(), EPSSolve(), EPSGetEigenpair()
251: @*/
252: PetscErrorCode EPSGetConverged(EPS eps,PetscInt *nconv)
253: {
254:   PetscFunctionBegin;
257:   EPSCheckSolved(eps,1);
258:   *nconv = eps->nconv;
259:   PetscFunctionReturn(PETSC_SUCCESS);
260: }

262: /*@
263:    EPSGetConvergedReason - Gets the reason why the EPSSolve() iteration was
264:    stopped.

266:    Not Collective

268:    Input Parameter:
269: .  eps - the eigensolver context

271:    Output Parameter:
272: .  reason - negative value indicates diverged, positive value converged

274:    Options Database Key:
275: .  -eps_converged_reason - print the reason to a viewer

277:    Notes:
278:    Possible values for reason are
279: +  EPS_CONVERGED_TOL - converged up to tolerance
280: .  EPS_CONVERGED_USER - converged due to a user-defined condition
281: .  EPS_DIVERGED_ITS - required more than max_it iterations to reach convergence
282: .  EPS_DIVERGED_BREAKDOWN - generic breakdown in method
283: -  EPS_DIVERGED_SYMMETRY_LOST - pseudo-Lanczos was not able to keep symmetry

285:    Can only be called after the call to EPSSolve() is complete.

287:    Level: intermediate

289: .seealso: EPSSetTolerances(), EPSSolve(), EPSConvergedReason
290: @*/
291: PetscErrorCode EPSGetConvergedReason(EPS eps,EPSConvergedReason *reason)
292: {
293:   PetscFunctionBegin;
296:   EPSCheckSolved(eps,1);
297:   *reason = eps->reason;
298:   PetscFunctionReturn(PETSC_SUCCESS);
299: }

301: /*@
302:    EPSGetInvariantSubspace - Gets an orthonormal basis of the computed invariant
303:    subspace.

305:    Collective

307:    Input Parameter:
308: .  eps - the eigensolver context

310:    Output Parameter:
311: .  v - an array of vectors

313:    Notes:
314:    This function should be called after EPSSolve() has finished.

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

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

326:    Level: intermediate

328: .seealso: EPSGetEigenpair(), EPSGetConverged(), EPSSolve()
329: @*/
330: PetscErrorCode EPSGetInvariantSubspace(EPS eps,Vec v[])
331: {
332:   PetscInt       i;
333:   BV             V=eps->V;
334:   Vec            w;

336:   PetscFunctionBegin;
340:   EPSCheckSolved(eps,1);
341:   PetscCheck(eps->ishermitian || eps->state!=EPS_STATE_EIGENVECTORS,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"EPSGetInvariantSubspace must be called before EPSGetEigenpair,EPSGetEigenvector or EPSComputeError");
342:   if (eps->balance!=EPS_BALANCE_NONE && eps->D) {
343:     PetscCall(BVDuplicateResize(eps->V,eps->nconv,&V));
344:     PetscCall(BVSetActiveColumns(eps->V,0,eps->nconv));
345:     PetscCall(BVCopy(eps->V,V));
346:     for (i=0;i<eps->nconv;i++) {
347:       PetscCall(BVGetColumn(V,i,&w));
348:       PetscCall(VecPointwiseDivide(w,w,eps->D));
349:       PetscCall(BVRestoreColumn(V,i,&w));
350:     }
351:     PetscCall(BVOrthogonalize(V,NULL));
352:   }
353:   for (i=0;i<eps->nconv;i++) PetscCall(BVCopyVec(V,i,v[i]));
354:   if (eps->balance!=EPS_BALANCE_NONE && eps->D) PetscCall(BVDestroy(&V));
355:   PetscFunctionReturn(PETSC_SUCCESS);
356: }

358: /*@C
359:    EPSGetEigenpair - Gets the i-th solution of the eigenproblem as computed by
360:    EPSSolve(). The solution consists in both the eigenvalue and the eigenvector.

362:    Collective

364:    Input Parameters:
365: +  eps - eigensolver context
366: -  i   - index of the solution

368:    Output Parameters:
369: +  eigr - real part of eigenvalue
370: .  eigi - imaginary part of eigenvalue
371: .  Vr   - real part of eigenvector
372: -  Vi   - imaginary part of eigenvector

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

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

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

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

392:    Level: beginner

394: .seealso: EPSGetEigenvalue(), EPSGetEigenvector(), EPSGetLeftEigenvector(), EPSSolve(),
395:           EPSGetConverged(), EPSSetWhichEigenpairs(), EPSGetInvariantSubspace()
396: @*/
397: PetscErrorCode EPSGetEigenpair(EPS eps,PetscInt i,PetscScalar *eigr,PetscScalar *eigi,Vec Vr,Vec Vi)
398: {
399:   PetscFunctionBegin;
402:   EPSCheckSolved(eps,1);
403:   PetscCheck(i>=0,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The index cannot be negative");
404:   PetscCheck(i<eps->nconv,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The index can be nconv-1 at most, see EPSGetConverged()");
405:   PetscCall(EPSGetEigenvalue(eps,i,eigr,eigi));
406:   if (Vr || Vi) PetscCall(EPSGetEigenvector(eps,i,Vr,Vi));
407:   PetscFunctionReturn(PETSC_SUCCESS);
408: }

410: /*@C
411:    EPSGetEigenvalue - Gets the i-th eigenvalue as computed by EPSSolve().

413:    Not Collective

415:    Input Parameters:
416: +  eps - eigensolver context
417: -  i   - index of the solution

419:    Output Parameters:
420: +  eigr - real part of eigenvalue
421: -  eigi - imaginary part of eigenvalue

423:    Notes:
424:    If the eigenvalue is real, then eigi is set to zero. If PETSc is
425:    configured with complex scalars the eigenvalue is stored
426:    directly in eigr (eigi is set to zero).

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

432:    Level: beginner

434: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs(), EPSGetEigenpair()
435: @*/
436: PetscErrorCode EPSGetEigenvalue(EPS eps,PetscInt i,PetscScalar *eigr,PetscScalar *eigi)
437: {
438:   PetscInt k;

440:   PetscFunctionBegin;
442:   EPSCheckSolved(eps,1);
443:   PetscCheck(i>=0,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The index cannot be negative");
444:   PetscCheck(i<eps->nconv,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The index can be nconv-1 at most, see EPSGetConverged()");
445:   k = eps->perm[i];
446: #if defined(PETSC_USE_COMPLEX)
447:   if (eigr) *eigr = eps->eigr[k];
448:   if (eigi) *eigi = 0;
449: #else
450:   if (eigr) *eigr = eps->eigr[k];
451:   if (eigi) *eigi = eps->eigi[k];
452: #endif
453:   PetscFunctionReturn(PETSC_SUCCESS);
454: }

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

459:    Collective

461:    Input Parameters:
462: +  eps - eigensolver context
463: -  i   - index of the solution

465:    Output Parameters:
466: +  Vr   - real part of eigenvector
467: -  Vi   - imaginary part of eigenvector

469:    Notes:
470:    The caller must provide valid Vec objects, i.e., they must be created
471:    by the calling program with e.g. MatCreateVecs().

473:    If the corresponding eigenvalue is real, then Vi is set to zero. If PETSc is
474:    configured with complex scalars the eigenvector is stored
475:    directly in Vr (Vi is set to zero). In any case, the user can pass NULL in Vr
476:    or Vi if one of them is not required.

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

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

486:    Level: beginner

488: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs(), EPSGetEigenpair(), EPSGetLeftEigenvector()
489: @*/
490: PetscErrorCode EPSGetEigenvector(EPS eps,PetscInt i,Vec Vr,Vec Vi)
491: {
492:   PetscInt       k;

494:   PetscFunctionBegin;
499:   EPSCheckSolved(eps,1);
500:   PetscCheck(i>=0,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The index cannot be negative");
501:   PetscCheck(i<eps->nconv,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The index can be nconv-1 at most, see EPSGetConverged()");
502:   PetscCall(EPSComputeVectors(eps));
503:   k = eps->perm[i];
504:   PetscCall(BV_GetEigenvector(eps->V,k,eps->eigi[k],Vr,Vi));
505:   PetscFunctionReturn(PETSC_SUCCESS);
506: }

508: /*@
509:    EPSGetLeftEigenvector - Gets the i-th left eigenvector as computed by EPSSolve().

511:    Collective

513:    Input Parameters:
514: +  eps - eigensolver context
515: -  i   - index of the solution

517:    Output Parameters:
518: +  Wr   - real part of left eigenvector
519: -  Wi   - imaginary part of left eigenvector

521:    Notes:
522:    The caller must provide valid Vec objects, i.e., they must be created
523:    by the calling program with e.g. MatCreateVecs().

525:    If the corresponding eigenvalue is real, then Wi is set to zero. If PETSc is
526:    configured with complex scalars the eigenvector is stored directly in Wr
527:    (Wi is set to zero). In any case, the user can pass NULL in Wr or Wi if
528:    one of them is not required.

530:    The index i should be a value between 0 and nconv-1 (see EPSGetConverged()).
531:    Eigensolutions are indexed according to the ordering criterion established
532:    with EPSSetWhichEigenpairs().

534:    Left eigenvectors are available only if the twosided flag was set, see
535:    EPSSetTwoSided().

537:    Level: intermediate

539: .seealso: EPSGetEigenvector(), EPSGetConverged(), EPSSetWhichEigenpairs(), EPSSetTwoSided()
540: @*/
541: PetscErrorCode EPSGetLeftEigenvector(EPS eps,PetscInt i,Vec Wr,Vec Wi)
542: {
543:   PetscInt       k;

545:   PetscFunctionBegin;
550:   EPSCheckSolved(eps,1);
551:   PetscCheck(eps->twosided,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Must request left vectors with EPSSetTwoSided");
552:   PetscCheck(i>=0,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The index cannot be negative");
553:   PetscCheck(i<eps->nconv,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The index can be nconv-1 at most, see EPSGetConverged()");
554:   PetscCall(EPSComputeVectors(eps));
555:   k = eps->perm[i];
556:   PetscCall(BV_GetEigenvector(eps->W,k,eps->eigi[k],Wr,Wi));
557:   PetscFunctionReturn(PETSC_SUCCESS);
558: }

560: /*@
561:    EPSGetErrorEstimate - Returns the error estimate associated to the i-th
562:    computed eigenpair.

564:    Not Collective

566:    Input Parameters:
567: +  eps - eigensolver context
568: -  i   - index of eigenpair

570:    Output Parameter:
571: .  errest - the error estimate

573:    Notes:
574:    This is the error estimate used internally by the eigensolver. The actual
575:    error bound can be computed with EPSComputeError(). See also the users
576:    manual for details.

578:    Level: advanced

580: .seealso: EPSComputeError()
581: @*/
582: PetscErrorCode EPSGetErrorEstimate(EPS eps,PetscInt i,PetscReal *errest)
583: {
584:   PetscFunctionBegin;
587:   EPSCheckSolved(eps,1);
588:   PetscCheck(i>=0,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The index cannot be negative");
589:   PetscCheck(i<eps->nconv,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The index can be nconv-1 at most, see EPSGetConverged()");
590:   *errest = eps->errest[eps->perm[i]];
591:   PetscFunctionReturn(PETSC_SUCCESS);
592: }

594: /*
595:    EPSComputeResidualNorm_Private - Computes the norm of the residual vector
596:    associated with an eigenpair.

598:    Input Parameters:
599:      trans - whether A' must be used instead of A
600:      kr,ki - eigenvalue
601:      xr,xi - eigenvector
602:      z     - three work vectors (the second one not referenced in complex scalars)
603: */
604: PetscErrorCode EPSComputeResidualNorm_Private(EPS eps,PetscBool trans,PetscScalar kr,PetscScalar ki,Vec xr,Vec xi,Vec *z,PetscReal *norm)
605: {
606:   PetscInt       nmat;
607:   Mat            A,B;
608:   Vec            u,w;
609:   PetscScalar    alpha;
610: #if !defined(PETSC_USE_COMPLEX)
611:   Vec            v;
612:   PetscReal      ni,nr;
613: #endif
614:   PetscErrorCode (*matmult)(Mat,Vec,Vec) = trans? MatMultHermitianTranspose: MatMult;

616:   PetscFunctionBegin;
617:   u = z[0]; w = z[2];
618:   PetscCall(STGetNumMatrices(eps->st,&nmat));
619:   PetscCall(STGetMatrix(eps->st,0,&A));
620:   if (nmat>1) PetscCall(STGetMatrix(eps->st,1,&B));

622: #if !defined(PETSC_USE_COMPLEX)
623:   v = z[1];
624:   if (ki == 0 || PetscAbsScalar(ki) < PetscAbsScalar(kr*PETSC_MACHINE_EPSILON)) {
625: #endif
626:     PetscCall((*matmult)(A,xr,u));                          /* u=A*x */
627:     if (PetscAbsScalar(kr) > PETSC_MACHINE_EPSILON) {
628:       if (nmat>1) PetscCall((*matmult)(B,xr,w));
629:       else PetscCall(VecCopy(xr,w));                        /* w=B*x */
630:       alpha = trans? -PetscConj(kr): -kr;
631:       PetscCall(VecAXPY(u,alpha,w));                        /* u=A*x-k*B*x */
632:     }
633:     PetscCall(VecNorm(u,NORM_2,norm));
634: #if !defined(PETSC_USE_COMPLEX)
635:   } else {
636:     PetscCall((*matmult)(A,xr,u));                          /* u=A*xr */
637:     if (SlepcAbsEigenvalue(kr,ki) > PETSC_MACHINE_EPSILON) {
638:       if (nmat>1) PetscCall((*matmult)(B,xr,v));
639:       else PetscCall(VecCopy(xr,v));                        /* v=B*xr */
640:       PetscCall(VecAXPY(u,-kr,v));                          /* u=A*xr-kr*B*xr */
641:       if (nmat>1) PetscCall((*matmult)(B,xi,w));
642:       else PetscCall(VecCopy(xi,w));                        /* w=B*xi */
643:       PetscCall(VecAXPY(u,trans?-ki:ki,w));                 /* u=A*xr-kr*B*xr+ki*B*xi */
644:     }
645:     PetscCall(VecNorm(u,NORM_2,&nr));
646:     PetscCall((*matmult)(A,xi,u));                          /* u=A*xi */
647:     if (SlepcAbsEigenvalue(kr,ki) > PETSC_MACHINE_EPSILON) {
648:       PetscCall(VecAXPY(u,-kr,w));                          /* u=A*xi-kr*B*xi */
649:       PetscCall(VecAXPY(u,trans?ki:-ki,v));                 /* u=A*xi-kr*B*xi-ki*B*xr */
650:     }
651:     PetscCall(VecNorm(u,NORM_2,&ni));
652:     *norm = SlepcAbsEigenvalue(nr,ni);
653:   }
654: #endif
655:   PetscFunctionReturn(PETSC_SUCCESS);
656: }

658: /*@
659:    EPSComputeError - Computes the error (based on the residual norm) associated
660:    with the i-th computed eigenpair.

662:    Collective

664:    Input Parameters:
665: +  eps  - the eigensolver context
666: .  i    - the solution index
667: -  type - the type of error to compute

669:    Output Parameter:
670: .  error - the error

672:    Notes:
673:    The error can be computed in various ways, all of them based on the residual
674:    norm ||Ax-kBx||_2 where k is the eigenvalue and x is the eigenvector.

676:    Level: beginner

678: .seealso: EPSErrorType, EPSSolve(), EPSGetErrorEstimate()
679: @*/
680: PetscErrorCode EPSComputeError(EPS eps,PetscInt i,EPSErrorType type,PetscReal *error)
681: {
682:   Mat            A,B;
683:   Vec            xr,xi,w[3];
684:   PetscReal      t,vecnorm=1.0,errorl;
685:   PetscScalar    kr,ki;
686:   PetscBool      flg;

688:   PetscFunctionBegin;
693:   EPSCheckSolved(eps,1);

695:   /* allocate work vectors */
696: #if defined(PETSC_USE_COMPLEX)
697:   PetscCall(EPSSetWorkVecs(eps,3));
698:   xi   = NULL;
699:   w[1] = NULL;
700: #else
701:   PetscCall(EPSSetWorkVecs(eps,5));
702:   xi   = eps->work[3];
703:   w[1] = eps->work[4];
704: #endif
705:   xr   = eps->work[0];
706:   w[0] = eps->work[1];
707:   w[2] = eps->work[2];

709:   /* compute residual norm */
710:   PetscCall(EPSGetEigenpair(eps,i,&kr,&ki,xr,xi));
711:   PetscCall(EPSComputeResidualNorm_Private(eps,PETSC_FALSE,kr,ki,xr,xi,w,error));

713:   /* compute 2-norm of eigenvector */
714:   if (eps->problem_type==EPS_GHEP) PetscCall(VecNorm(xr,NORM_2,&vecnorm));

716:   /* if two-sided, compute left residual norm and take the maximum */
717:   if (eps->twosided) {
718:     PetscCall(EPSGetLeftEigenvector(eps,i,xr,xi));
719:     PetscCall(EPSComputeResidualNorm_Private(eps,PETSC_TRUE,kr,ki,xr,xi,w,&errorl));
720:     *error = PetscMax(*error,errorl);
721:   }

723:   /* compute error */
724:   switch (type) {
725:     case EPS_ERROR_ABSOLUTE:
726:       break;
727:     case EPS_ERROR_RELATIVE:
728:       *error /= SlepcAbsEigenvalue(kr,ki)*vecnorm;
729:       break;
730:     case EPS_ERROR_BACKWARD:
731:       /* initialization of matrix norms */
732:       if (!eps->nrma) {
733:         PetscCall(STGetMatrix(eps->st,0,&A));
734:         PetscCall(MatHasOperation(A,MATOP_NORM,&flg));
735:         PetscCheck(flg,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONG,"The computation of backward errors requires a matrix norm operation");
736:         PetscCall(MatNorm(A,NORM_INFINITY,&eps->nrma));
737:       }
738:       if (eps->isgeneralized) {
739:         if (!eps->nrmb) {
740:           PetscCall(STGetMatrix(eps->st,1,&B));
741:           PetscCall(MatHasOperation(B,MATOP_NORM,&flg));
742:           PetscCheck(flg,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONG,"The computation of backward errors requires a matrix norm operation");
743:           PetscCall(MatNorm(B,NORM_INFINITY,&eps->nrmb));
744:         }
745:       } else eps->nrmb = 1.0;
746:       t = SlepcAbsEigenvalue(kr,ki);
747:       *error /= (eps->nrma+t*eps->nrmb)*vecnorm;
748:       break;
749:     default:
750:       SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Invalid error type");
751:   }
752:   PetscFunctionReturn(PETSC_SUCCESS);
753: }

755: /*
756:    EPSGetStartVector - Generate a suitable vector to be used as the starting vector
757:    for the recurrence that builds the right subspace.

759:    Collective

761:    Input Parameters:
762: +  eps - the eigensolver context
763: -  i   - iteration number

765:    Output Parameters:
766: .  breakdown - flag indicating that a breakdown has occurred

768:    Notes:
769:    The start vector is computed from another vector: for the first step (i=0),
770:    the first initial vector is used (see EPSSetInitialSpace()); otherwise a random
771:    vector is created. Then this vector is forced to be in the range of OP (only
772:    for generalized definite problems) and orthonormalized with respect to all
773:    V-vectors up to i-1. The resulting vector is placed in V[i].

775:    The flag breakdown is set to true if either i=0 and the vector belongs to the
776:    deflation space, or i>0 and the vector is linearly dependent with respect
777:    to the V-vectors.
778: */
779: PetscErrorCode EPSGetStartVector(EPS eps,PetscInt i,PetscBool *breakdown)
780: {
781:   PetscReal      norm;
782:   PetscBool      lindep;
783:   Vec            w,z;

785:   PetscFunctionBegin;

789:   /* For the first step, use the first initial vector, otherwise a random one */
790:   if (i>0 || eps->nini==0) PetscCall(BVSetRandomColumn(eps->V,i));

792:   /* Force the vector to be in the range of OP for definite generalized problems */
793:   if (eps->ispositive || (eps->isgeneralized && eps->ishermitian)) {
794:     PetscCall(BVCreateVec(eps->V,&w));
795:     PetscCall(BVCopyVec(eps->V,i,w));
796:     PetscCall(BVGetColumn(eps->V,i,&z));
797:     PetscCall(STApply(eps->st,w,z));
798:     PetscCall(BVRestoreColumn(eps->V,i,&z));
799:     PetscCall(VecDestroy(&w));
800:   }

802:   /* Orthonormalize the vector with respect to previous vectors */
803:   PetscCall(BVOrthogonalizeColumn(eps->V,i,NULL,&norm,&lindep));
804:   if (breakdown) *breakdown = lindep;
805:   else if (lindep || norm == 0.0) {
806:     PetscCheck(i,PetscObjectComm((PetscObject)eps),PETSC_ERR_PLIB,"Initial vector is zero or belongs to the deflation space");
807:     PetscCheck(!i,PetscObjectComm((PetscObject)eps),PETSC_ERR_CONV_FAILED,"Unable to generate more start vectors");
808:   }
809:   PetscCall(BVScaleColumn(eps->V,i,1.0/norm));
810:   PetscFunctionReturn(PETSC_SUCCESS);
811: }

813: /*
814:    EPSGetLeftStartVector - Generate a suitable vector to be used as the left starting
815:    vector for the recurrence that builds the left subspace. See EPSGetStartVector().
816: */
817: PetscErrorCode EPSGetLeftStartVector(EPS eps,PetscInt i,PetscBool *breakdown)
818: {
819:   PetscReal      norm;
820:   PetscBool      lindep;

822:   PetscFunctionBegin;

826:   /* For the first step, use the first initial vector, otherwise a random one */
827:   if (i>0 || eps->ninil==0) PetscCall(BVSetRandomColumn(eps->W,i));

829:   /* Orthonormalize the vector with respect to previous vectors */
830:   PetscCall(BVOrthogonalizeColumn(eps->W,i,NULL,&norm,&lindep));
831:   if (breakdown) *breakdown = lindep;
832:   else if (lindep || norm == 0.0) {
833:     PetscCheck(i,PetscObjectComm((PetscObject)eps),PETSC_ERR_PLIB,"Left initial vector is zero");
834:     SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_CONV_FAILED,"Unable to generate more left start vectors");
835:   }
836:   PetscCall(BVScaleColumn(eps->W,i,1.0/norm));
837:   PetscFunctionReturn(PETSC_SUCCESS);
838: }