Actual source code: epssolve.c
slepc-3.20.1 2023-11-27
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) do {t=a;a=b;b=t;} while (0)
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: PetscBool hasname;
125: STMatMode matmode;
126: Mat A,B;
128: PetscFunctionBegin;
130: if (eps->state>=EPS_STATE_SOLVED) PetscFunctionReturn(PETSC_SUCCESS);
131: PetscCall(PetscLogEventBegin(EPS_Solve,eps,0,0,0));
133: /* Call setup */
134: PetscCall(EPSSetUp(eps));
135: eps->nconv = 0;
136: eps->its = 0;
137: for (i=0;i<eps->ncv;i++) {
138: eps->eigr[i] = 0.0;
139: eps->eigi[i] = 0.0;
140: eps->errest[i] = 0.0;
141: eps->perm[i] = i;
142: }
143: PetscCall(EPSViewFromOptions(eps,NULL,"-eps_view_pre"));
144: PetscCall(RGViewFromOptions(eps->rg,NULL,"-rg_view"));
146: /* Call solver */
147: PetscUseTypeMethod(eps,solve);
148: PetscCheck(eps->reason,PetscObjectComm((PetscObject)eps),PETSC_ERR_PLIB,"Internal error, solver returned without setting converged reason");
149: eps->state = EPS_STATE_SOLVED;
151: /* Only the first nconv columns contain useful information (except in CISS) */
152: PetscCall(BVSetActiveColumns(eps->V,0,eps->nconv));
153: if (eps->twosided) PetscCall(BVSetActiveColumns(eps->W,0,eps->nconv));
155: /* If inplace, purify eigenvectors before reverting operator */
156: PetscCall(STGetMatMode(eps->st,&matmode));
157: if (matmode == ST_MATMODE_INPLACE && eps->ispositive) PetscCall(EPSComputeVectors(eps));
158: PetscCall(STPostSolve(eps->st));
160: /* Map eigenvalues back to the original problem if appropriate */
161: PetscCall(EPSComputeValues(eps));
163: #if !defined(PETSC_USE_COMPLEX)
164: /* Reorder conjugate eigenvalues (positive imaginary first) */
165: for (i=0;i<eps->nconv-1;i++) {
166: if (eps->eigi[i] != 0) {
167: if (eps->eigi[i] < 0) {
168: eps->eigi[i] = -eps->eigi[i];
169: eps->eigi[i+1] = -eps->eigi[i+1];
170: /* the next correction only works with eigenvectors */
171: PetscCall(EPSComputeVectors(eps));
172: PetscCall(BVScaleColumn(eps->V,i+1,-1.0));
173: }
174: i++;
175: }
176: }
177: #endif
179: /* Sort eigenvalues according to eps->which parameter */
180: PetscCall(SlepcSortEigenvalues(eps->sc,eps->nconv,eps->eigr,eps->eigi,eps->perm));
181: PetscCall(PetscLogEventEnd(EPS_Solve,eps,0,0,0));
183: /* Various viewers */
184: PetscCall(EPSViewFromOptions(eps,NULL,"-eps_view"));
185: PetscCall(EPSConvergedReasonViewFromOptions(eps));
186: PetscCall(EPSErrorViewFromOptions(eps));
187: PetscCall(EPSValuesViewFromOptions(eps));
188: PetscCall(EPSVectorsViewFromOptions(eps));
190: PetscCall(PetscOptionsHasName(NULL,NULL,"-eps_view_mat0",&hasname));
191: if (hasname) {
192: PetscCall(EPSGetOperators(eps,&A,NULL));
193: PetscCall(MatViewFromOptions(A,(PetscObject)eps,"-eps_view_mat0"));
194: }
195: if (eps->isgeneralized) {
196: PetscCall(PetscOptionsHasName(NULL,NULL,"-eps_view_mat1",&hasname));
197: if (hasname) {
198: PetscCall(EPSGetOperators(eps,NULL,&B));
199: PetscCall(MatViewFromOptions(B,(PetscObject)eps,"-eps_view_mat1"));
200: }
201: }
203: /* Remove deflation and initial subspaces */
204: if (eps->nds) {
205: PetscCall(BVSetNumConstraints(eps->V,0));
206: eps->nds = 0;
207: }
208: eps->nini = 0;
209: PetscFunctionReturn(PETSC_SUCCESS);
210: }
212: /*@
213: EPSGetIterationNumber - Gets the current iteration number. If the
214: call to EPSSolve() is complete, then it returns the number of iterations
215: carried out by the solution method.
217: Not Collective
219: Input Parameter:
220: . eps - the eigensolver context
222: Output Parameter:
223: . its - number of iterations
225: Note:
226: During the i-th iteration this call returns i-1. If EPSSolve() is
227: complete, then parameter "its" contains either the iteration number at
228: which convergence was successfully reached, or failure was detected.
229: Call EPSGetConvergedReason() to determine if the solver converged or
230: failed and why.
232: Level: intermediate
234: .seealso: EPSGetConvergedReason(), EPSSetTolerances()
235: @*/
236: PetscErrorCode EPSGetIterationNumber(EPS eps,PetscInt *its)
237: {
238: PetscFunctionBegin;
240: PetscAssertPointer(its,2);
241: *its = eps->its;
242: PetscFunctionReturn(PETSC_SUCCESS);
243: }
245: /*@
246: EPSGetConverged - Gets the number of converged eigenpairs.
248: Not Collective
250: Input Parameter:
251: . eps - the eigensolver context
253: Output Parameter:
254: . nconv - number of converged eigenpairs
256: Note:
257: This function should be called after EPSSolve() has finished.
259: Level: beginner
261: .seealso: EPSSetDimensions(), EPSSolve(), EPSGetEigenpair()
262: @*/
263: PetscErrorCode EPSGetConverged(EPS eps,PetscInt *nconv)
264: {
265: PetscFunctionBegin;
267: PetscAssertPointer(nconv,2);
268: EPSCheckSolved(eps,1);
269: *nconv = eps->nconv;
270: PetscFunctionReturn(PETSC_SUCCESS);
271: }
273: /*@
274: EPSGetConvergedReason - Gets the reason why the EPSSolve() iteration was
275: stopped.
277: Not Collective
279: Input Parameter:
280: . eps - the eigensolver context
282: Output Parameter:
283: . reason - negative value indicates diverged, positive value converged
285: Options Database Key:
286: . -eps_converged_reason - print the reason to a viewer
288: Notes:
289: Possible values for reason are
290: + EPS_CONVERGED_TOL - converged up to tolerance
291: . EPS_CONVERGED_USER - converged due to a user-defined condition
292: . EPS_DIVERGED_ITS - required more than max_it iterations to reach convergence
293: . EPS_DIVERGED_BREAKDOWN - generic breakdown in method
294: - EPS_DIVERGED_SYMMETRY_LOST - pseudo-Lanczos was not able to keep symmetry
296: Can only be called after the call to EPSSolve() is complete.
298: Level: intermediate
300: .seealso: EPSSetTolerances(), EPSSolve(), EPSConvergedReason
301: @*/
302: PetscErrorCode EPSGetConvergedReason(EPS eps,EPSConvergedReason *reason)
303: {
304: PetscFunctionBegin;
306: PetscAssertPointer(reason,2);
307: EPSCheckSolved(eps,1);
308: *reason = eps->reason;
309: PetscFunctionReturn(PETSC_SUCCESS);
310: }
312: /*@
313: EPSGetInvariantSubspace - Gets an orthonormal basis of the computed invariant
314: subspace.
316: Collective
318: Input Parameter:
319: . eps - the eigensolver context
321: Output Parameter:
322: . v - an array of vectors
324: Notes:
325: This function should be called after EPSSolve() has finished.
327: The user should provide in v an array of nconv vectors, where nconv is
328: the value returned by EPSGetConverged().
330: The first k vectors returned in v span an invariant subspace associated
331: with the first k computed eigenvalues (note that this is not true if the
332: k-th eigenvalue is complex and matrix A is real; in this case the first
333: k+1 vectors should be used). An invariant subspace X of A satisfies Ax
334: in X for all x in X (a similar definition applies for generalized
335: eigenproblems).
337: Level: intermediate
339: .seealso: EPSGetEigenpair(), EPSGetConverged(), EPSSolve()
340: @*/
341: PetscErrorCode EPSGetInvariantSubspace(EPS eps,Vec v[])
342: {
343: PetscInt i;
344: BV V=eps->V;
345: Vec w;
347: PetscFunctionBegin;
349: PetscAssertPointer(v,2);
351: EPSCheckSolved(eps,1);
352: PetscCheck(eps->ishermitian || eps->state!=EPS_STATE_EIGENVECTORS,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"EPSGetInvariantSubspace must be called before EPSGetEigenpair,EPSGetEigenvector or EPSComputeError");
353: if (eps->balance!=EPS_BALANCE_NONE && eps->D) {
354: PetscCall(BVDuplicateResize(eps->V,eps->nconv,&V));
355: PetscCall(BVSetActiveColumns(eps->V,0,eps->nconv));
356: PetscCall(BVCopy(eps->V,V));
357: for (i=0;i<eps->nconv;i++) {
358: PetscCall(BVGetColumn(V,i,&w));
359: PetscCall(VecPointwiseDivide(w,w,eps->D));
360: PetscCall(BVRestoreColumn(V,i,&w));
361: }
362: PetscCall(BVOrthogonalize(V,NULL));
363: }
364: for (i=0;i<eps->nconv;i++) PetscCall(BVCopyVec(V,i,v[i]));
365: if (eps->balance!=EPS_BALANCE_NONE && eps->D) PetscCall(BVDestroy(&V));
366: PetscFunctionReturn(PETSC_SUCCESS);
367: }
369: /*@C
370: EPSGetEigenpair - Gets the i-th solution of the eigenproblem as computed by
371: EPSSolve(). The solution consists in both the eigenvalue and the eigenvector.
373: Collective
375: Input Parameters:
376: + eps - eigensolver context
377: - i - index of the solution
379: Output Parameters:
380: + eigr - real part of eigenvalue
381: . eigi - imaginary part of eigenvalue
382: . Vr - real part of eigenvector
383: - Vi - imaginary part of eigenvector
385: Notes:
386: It is allowed to pass NULL for Vr and Vi, if the eigenvector is not
387: required. Otherwise, the caller must provide valid Vec objects, i.e.,
388: they must be created by the calling program with e.g. MatCreateVecs().
390: If the eigenvalue is real, then eigi and Vi are set to zero. If PETSc is
391: configured with complex scalars the eigenvalue is stored
392: directly in eigr (eigi is set to zero) and the eigenvector in Vr (Vi is
393: set to zero). In both cases, the user can pass NULL in eigi and Vi.
395: The index i should be a value between 0 and nconv-1 (see EPSGetConverged()).
396: Eigenpairs are indexed according to the ordering criterion established
397: with EPSSetWhichEigenpairs().
399: The 2-norm of the eigenvector is one unless the problem is generalized
400: Hermitian. In this case the eigenvector is normalized with respect to the
401: norm defined by the B matrix.
403: Level: beginner
405: .seealso: EPSGetEigenvalue(), EPSGetEigenvector(), EPSGetLeftEigenvector(), EPSSolve(),
406: EPSGetConverged(), EPSSetWhichEigenpairs(), EPSGetInvariantSubspace()
407: @*/
408: PetscErrorCode EPSGetEigenpair(EPS eps,PetscInt i,PetscScalar *eigr,PetscScalar *eigi,Vec Vr,Vec Vi)
409: {
410: PetscFunctionBegin;
413: EPSCheckSolved(eps,1);
414: PetscCheck(i>=0,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The index cannot be negative");
415: PetscCheck(i<eps->nconv,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The index can be nconv-1 at most, see EPSGetConverged()");
416: PetscCall(EPSGetEigenvalue(eps,i,eigr,eigi));
417: if (Vr || Vi) PetscCall(EPSGetEigenvector(eps,i,Vr,Vi));
418: PetscFunctionReturn(PETSC_SUCCESS);
419: }
421: /*@C
422: EPSGetEigenvalue - Gets the i-th eigenvalue as computed by EPSSolve().
424: Not Collective
426: Input Parameters:
427: + eps - eigensolver context
428: - i - index of the solution
430: Output Parameters:
431: + eigr - real part of eigenvalue
432: - eigi - imaginary part of eigenvalue
434: Notes:
435: If the eigenvalue is real, then eigi is set to zero. If PETSc is
436: configured with complex scalars the eigenvalue is stored
437: directly in eigr (eigi is set to zero).
439: The index i should be a value between 0 and nconv-1 (see EPSGetConverged()).
440: Eigenpairs are indexed according to the ordering criterion established
441: with EPSSetWhichEigenpairs().
443: Level: beginner
445: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs(), EPSGetEigenpair()
446: @*/
447: PetscErrorCode EPSGetEigenvalue(EPS eps,PetscInt i,PetscScalar *eigr,PetscScalar *eigi)
448: {
449: PetscInt k;
451: PetscFunctionBegin;
453: EPSCheckSolved(eps,1);
454: PetscCheck(i>=0,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The index cannot be negative");
455: PetscCheck(i<eps->nconv,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The index can be nconv-1 at most, see EPSGetConverged()");
456: k = eps->perm[i];
457: #if defined(PETSC_USE_COMPLEX)
458: if (eigr) *eigr = eps->eigr[k];
459: if (eigi) *eigi = 0;
460: #else
461: if (eigr) *eigr = eps->eigr[k];
462: if (eigi) *eigi = eps->eigi[k];
463: #endif
464: PetscFunctionReturn(PETSC_SUCCESS);
465: }
467: /*@
468: EPSGetEigenvector - Gets the i-th right eigenvector as computed by EPSSolve().
470: Collective
472: Input Parameters:
473: + eps - eigensolver context
474: - i - index of the solution
476: Output Parameters:
477: + Vr - real part of eigenvector
478: - Vi - imaginary part of eigenvector
480: Notes:
481: The caller must provide valid Vec objects, i.e., they must be created
482: by the calling program with e.g. MatCreateVecs().
484: If the corresponding eigenvalue is real, then Vi is set to zero. If PETSc is
485: configured with complex scalars the eigenvector is stored
486: directly in Vr (Vi is set to zero). In any case, the user can pass NULL in Vr
487: or Vi if one of them is not required.
489: The index i should be a value between 0 and nconv-1 (see EPSGetConverged()).
490: Eigenpairs are indexed according to the ordering criterion established
491: with EPSSetWhichEigenpairs().
493: The 2-norm of the eigenvector is one unless the problem is generalized
494: Hermitian. In this case the eigenvector is normalized with respect to the
495: norm defined by the B matrix.
497: Level: beginner
499: .seealso: EPSSolve(), EPSGetConverged(), EPSSetWhichEigenpairs(), EPSGetEigenpair(), EPSGetLeftEigenvector()
500: @*/
501: PetscErrorCode EPSGetEigenvector(EPS eps,PetscInt i,Vec Vr,Vec Vi)
502: {
503: PetscInt k;
505: PetscFunctionBegin;
510: EPSCheckSolved(eps,1);
511: PetscCheck(i>=0,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The index cannot be negative");
512: PetscCheck(i<eps->nconv,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The index can be nconv-1 at most, see EPSGetConverged()");
513: PetscCall(EPSComputeVectors(eps));
514: k = eps->perm[i];
515: PetscCall(BV_GetEigenvector(eps->V,k,eps->eigi[k],Vr,Vi));
516: PetscFunctionReturn(PETSC_SUCCESS);
517: }
519: /*@
520: EPSGetLeftEigenvector - Gets the i-th left eigenvector as computed by EPSSolve().
522: Collective
524: Input Parameters:
525: + eps - eigensolver context
526: - i - index of the solution
528: Output Parameters:
529: + Wr - real part of left eigenvector
530: - Wi - imaginary part of left eigenvector
532: Notes:
533: The caller must provide valid Vec objects, i.e., they must be created
534: by the calling program with e.g. MatCreateVecs().
536: If the corresponding eigenvalue is real, then Wi is set to zero. If PETSc is
537: configured with complex scalars the eigenvector is stored directly in Wr
538: (Wi is set to zero). In any case, the user can pass NULL in Wr or Wi if
539: one of them is not required.
541: The index i should be a value between 0 and nconv-1 (see EPSGetConverged()).
542: Eigensolutions are indexed according to the ordering criterion established
543: with EPSSetWhichEigenpairs().
545: Left eigenvectors are available only if the twosided flag was set, see
546: EPSSetTwoSided().
548: Level: intermediate
550: .seealso: EPSGetEigenvector(), EPSGetConverged(), EPSSetWhichEigenpairs(), EPSSetTwoSided()
551: @*/
552: PetscErrorCode EPSGetLeftEigenvector(EPS eps,PetscInt i,Vec Wr,Vec Wi)
553: {
554: PetscInt k;
556: PetscFunctionBegin;
561: EPSCheckSolved(eps,1);
562: PetscCheck(eps->twosided,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONGSTATE,"Must request left vectors with EPSSetTwoSided");
563: PetscCheck(i>=0,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The index cannot be negative");
564: PetscCheck(i<eps->nconv,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The index can be nconv-1 at most, see EPSGetConverged()");
565: PetscCall(EPSComputeVectors(eps));
566: k = eps->perm[i];
567: PetscCall(BV_GetEigenvector(eps->W,k,eps->eigi[k],Wr,Wi));
568: PetscFunctionReturn(PETSC_SUCCESS);
569: }
571: /*@
572: EPSGetErrorEstimate - Returns the error estimate associated to the i-th
573: computed eigenpair.
575: Not Collective
577: Input Parameters:
578: + eps - eigensolver context
579: - i - index of eigenpair
581: Output Parameter:
582: . errest - the error estimate
584: Notes:
585: This is the error estimate used internally by the eigensolver. The actual
586: error bound can be computed with EPSComputeError(). See also the users
587: manual for details.
589: Level: advanced
591: .seealso: EPSComputeError()
592: @*/
593: PetscErrorCode EPSGetErrorEstimate(EPS eps,PetscInt i,PetscReal *errest)
594: {
595: PetscFunctionBegin;
597: PetscAssertPointer(errest,3);
598: EPSCheckSolved(eps,1);
599: PetscCheck(i>=0,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The index cannot be negative");
600: PetscCheck(i<eps->nconv,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The index can be nconv-1 at most, see EPSGetConverged()");
601: *errest = eps->errest[eps->perm[i]];
602: PetscFunctionReturn(PETSC_SUCCESS);
603: }
605: /*
606: EPSComputeResidualNorm_Private - Computes the norm of the residual vector
607: associated with an eigenpair.
609: Input Parameters:
610: trans - whether A' must be used instead of A
611: kr,ki - eigenvalue
612: xr,xi - eigenvector
613: z - three work vectors (the second one not referenced in complex scalars)
614: */
615: PetscErrorCode EPSComputeResidualNorm_Private(EPS eps,PetscBool trans,PetscScalar kr,PetscScalar ki,Vec xr,Vec xi,Vec *z,PetscReal *norm)
616: {
617: PetscInt nmat;
618: Mat A,B;
619: Vec u,w;
620: PetscScalar alpha;
621: #if !defined(PETSC_USE_COMPLEX)
622: Vec v;
623: PetscReal ni,nr;
624: #endif
625: PetscErrorCode (*matmult)(Mat,Vec,Vec) = trans? MatMultHermitianTranspose: MatMult;
627: PetscFunctionBegin;
628: u = z[0]; w = z[2];
629: PetscCall(STGetNumMatrices(eps->st,&nmat));
630: PetscCall(STGetMatrix(eps->st,0,&A));
631: if (nmat>1) PetscCall(STGetMatrix(eps->st,1,&B));
633: #if !defined(PETSC_USE_COMPLEX)
634: v = z[1];
635: if (ki == 0 || PetscAbsScalar(ki) < PetscAbsScalar(kr*PETSC_MACHINE_EPSILON)) {
636: #endif
637: PetscCall((*matmult)(A,xr,u)); /* u=A*x */
638: if (PetscAbsScalar(kr) > PETSC_MACHINE_EPSILON) {
639: if (nmat>1) PetscCall((*matmult)(B,xr,w));
640: else PetscCall(VecCopy(xr,w)); /* w=B*x */
641: alpha = trans? -PetscConj(kr): -kr;
642: PetscCall(VecAXPY(u,alpha,w)); /* u=A*x-k*B*x */
643: }
644: PetscCall(VecNorm(u,NORM_2,norm));
645: #if !defined(PETSC_USE_COMPLEX)
646: } else {
647: PetscCall((*matmult)(A,xr,u)); /* u=A*xr */
648: if (SlepcAbsEigenvalue(kr,ki) > PETSC_MACHINE_EPSILON) {
649: if (nmat>1) PetscCall((*matmult)(B,xr,v));
650: else PetscCall(VecCopy(xr,v)); /* v=B*xr */
651: PetscCall(VecAXPY(u,-kr,v)); /* u=A*xr-kr*B*xr */
652: if (nmat>1) PetscCall((*matmult)(B,xi,w));
653: else PetscCall(VecCopy(xi,w)); /* w=B*xi */
654: PetscCall(VecAXPY(u,trans?-ki:ki,w)); /* u=A*xr-kr*B*xr+ki*B*xi */
655: }
656: PetscCall(VecNorm(u,NORM_2,&nr));
657: PetscCall((*matmult)(A,xi,u)); /* u=A*xi */
658: if (SlepcAbsEigenvalue(kr,ki) > PETSC_MACHINE_EPSILON) {
659: PetscCall(VecAXPY(u,-kr,w)); /* u=A*xi-kr*B*xi */
660: PetscCall(VecAXPY(u,trans?ki:-ki,v)); /* u=A*xi-kr*B*xi-ki*B*xr */
661: }
662: PetscCall(VecNorm(u,NORM_2,&ni));
663: *norm = SlepcAbsEigenvalue(nr,ni);
664: }
665: #endif
666: PetscFunctionReturn(PETSC_SUCCESS);
667: }
669: /*@
670: EPSComputeError - Computes the error (based on the residual norm) associated
671: with the i-th computed eigenpair.
673: Collective
675: Input Parameters:
676: + eps - the eigensolver context
677: . i - the solution index
678: - type - the type of error to compute
680: Output Parameter:
681: . error - the error
683: Notes:
684: The error can be computed in various ways, all of them based on the residual
685: norm ||Ax-kBx||_2 where k is the eigenvalue and x is the eigenvector.
687: Level: beginner
689: .seealso: EPSErrorType, EPSSolve(), EPSGetErrorEstimate()
690: @*/
691: PetscErrorCode EPSComputeError(EPS eps,PetscInt i,EPSErrorType type,PetscReal *error)
692: {
693: Mat A,B;
694: Vec xr,xi,w[3];
695: PetscReal t,vecnorm=1.0,errorl;
696: PetscScalar kr,ki;
697: PetscBool flg;
699: PetscFunctionBegin;
703: PetscAssertPointer(error,4);
704: EPSCheckSolved(eps,1);
706: /* allocate work vectors */
707: #if defined(PETSC_USE_COMPLEX)
708: PetscCall(EPSSetWorkVecs(eps,3));
709: xi = NULL;
710: w[1] = NULL;
711: #else
712: PetscCall(EPSSetWorkVecs(eps,5));
713: xi = eps->work[3];
714: w[1] = eps->work[4];
715: #endif
716: xr = eps->work[0];
717: w[0] = eps->work[1];
718: w[2] = eps->work[2];
720: /* compute residual norm */
721: PetscCall(EPSGetEigenpair(eps,i,&kr,&ki,xr,xi));
722: PetscCall(EPSComputeResidualNorm_Private(eps,PETSC_FALSE,kr,ki,xr,xi,w,error));
724: /* compute 2-norm of eigenvector */
725: if (eps->problem_type==EPS_GHEP) PetscCall(VecNorm(xr,NORM_2,&vecnorm));
727: /* if two-sided, compute left residual norm and take the maximum */
728: if (eps->twosided) {
729: PetscCall(EPSGetLeftEigenvector(eps,i,xr,xi));
730: PetscCall(EPSComputeResidualNorm_Private(eps,PETSC_TRUE,kr,ki,xr,xi,w,&errorl));
731: *error = PetscMax(*error,errorl);
732: }
734: /* compute error */
735: switch (type) {
736: case EPS_ERROR_ABSOLUTE:
737: break;
738: case EPS_ERROR_RELATIVE:
739: *error /= SlepcAbsEigenvalue(kr,ki)*vecnorm;
740: break;
741: case EPS_ERROR_BACKWARD:
742: /* initialization of matrix norms */
743: if (!eps->nrma) {
744: PetscCall(STGetMatrix(eps->st,0,&A));
745: PetscCall(MatHasOperation(A,MATOP_NORM,&flg));
746: PetscCheck(flg,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONG,"The computation of backward errors requires a matrix norm operation");
747: PetscCall(MatNorm(A,NORM_INFINITY,&eps->nrma));
748: }
749: if (eps->isgeneralized) {
750: if (!eps->nrmb) {
751: PetscCall(STGetMatrix(eps->st,1,&B));
752: PetscCall(MatHasOperation(B,MATOP_NORM,&flg));
753: PetscCheck(flg,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_WRONG,"The computation of backward errors requires a matrix norm operation");
754: PetscCall(MatNorm(B,NORM_INFINITY,&eps->nrmb));
755: }
756: } else eps->nrmb = 1.0;
757: t = SlepcAbsEigenvalue(kr,ki);
758: *error /= (eps->nrma+t*eps->nrmb)*vecnorm;
759: break;
760: default:
761: SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"Invalid error type");
762: }
763: PetscFunctionReturn(PETSC_SUCCESS);
764: }
766: /*
767: EPSGetStartVector - Generate a suitable vector to be used as the starting vector
768: for the recurrence that builds the right subspace.
770: Collective
772: Input Parameters:
773: + eps - the eigensolver context
774: - i - iteration number
776: Output Parameters:
777: . breakdown - flag indicating that a breakdown has occurred
779: Notes:
780: The start vector is computed from another vector: for the first step (i=0),
781: the first initial vector is used (see EPSSetInitialSpace()); otherwise a random
782: vector is created. Then this vector is forced to be in the range of OP (only
783: for generalized definite problems) and orthonormalized with respect to all
784: V-vectors up to i-1. The resulting vector is placed in V[i].
786: The flag breakdown is set to true if either i=0 and the vector belongs to the
787: deflation space, or i>0 and the vector is linearly dependent with respect
788: to the V-vectors.
789: */
790: PetscErrorCode EPSGetStartVector(EPS eps,PetscInt i,PetscBool *breakdown)
791: {
792: PetscReal norm;
793: PetscBool lindep;
794: Vec w,z;
796: PetscFunctionBegin;
800: /* For the first step, use the first initial vector, otherwise a random one */
801: if (i>0 || eps->nini==0) PetscCall(BVSetRandomColumn(eps->V,i));
803: /* Force the vector to be in the range of OP for definite generalized problems */
804: if (eps->ispositive || (eps->isgeneralized && eps->ishermitian)) {
805: PetscCall(BVCreateVec(eps->V,&w));
806: PetscCall(BVCopyVec(eps->V,i,w));
807: PetscCall(BVGetColumn(eps->V,i,&z));
808: PetscCall(STApply(eps->st,w,z));
809: PetscCall(BVRestoreColumn(eps->V,i,&z));
810: PetscCall(VecDestroy(&w));
811: }
813: /* Orthonormalize the vector with respect to previous vectors */
814: PetscCall(BVOrthogonalizeColumn(eps->V,i,NULL,&norm,&lindep));
815: if (breakdown) *breakdown = lindep;
816: else if (lindep || norm == 0.0) {
817: PetscCheck(i,PetscObjectComm((PetscObject)eps),PETSC_ERR_PLIB,"Initial vector is zero or belongs to the deflation space");
818: PetscCheck(!i,PetscObjectComm((PetscObject)eps),PETSC_ERR_CONV_FAILED,"Unable to generate more start vectors");
819: }
820: PetscCall(BVScaleColumn(eps->V,i,1.0/norm));
821: PetscFunctionReturn(PETSC_SUCCESS);
822: }
824: /*
825: EPSGetLeftStartVector - Generate a suitable vector to be used as the left starting
826: vector for the recurrence that builds the left subspace. See EPSGetStartVector().
827: */
828: PetscErrorCode EPSGetLeftStartVector(EPS eps,PetscInt i,PetscBool *breakdown)
829: {
830: PetscReal norm;
831: PetscBool lindep;
833: PetscFunctionBegin;
837: /* For the first step, use the first initial vector, otherwise a random one */
838: if (i>0 || eps->ninil==0) PetscCall(BVSetRandomColumn(eps->W,i));
840: /* Orthonormalize the vector with respect to previous vectors */
841: PetscCall(BVOrthogonalizeColumn(eps->W,i,NULL,&norm,&lindep));
842: if (breakdown) *breakdown = lindep;
843: else if (lindep || norm == 0.0) {
844: PetscCheck(i,PetscObjectComm((PetscObject)eps),PETSC_ERR_PLIB,"Left initial vector is zero");
845: SETERRQ(PetscObjectComm((PetscObject)eps),PETSC_ERR_CONV_FAILED,"Unable to generate more left start vectors");
846: }
847: PetscCall(BVScaleColumn(eps->W,i,1.0/norm));
848: PetscFunctionReturn(PETSC_SUCCESS);
849: }