Actual source code: epssolve.c
slepc-3.19.0 2023-03-31
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: }