1: /*
2: PEP routines related to the solution process.
4: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
5: SLEPc - Scalable Library for Eigenvalue Problem Computations
6: Copyright (c) 2002-2016, 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/pepimpl.h> /*I "slepcpep.h" I*/
25: #include <petscdraw.h>
29: PetscErrorCode PEPComputeVectors(PEP pep) 30: {
34: PEPCheckSolved(pep,1);
35: switch (pep->state) {
36: case PEP_STATE_SOLVED:
37: if (pep->ops->computevectors) {
38: (*pep->ops->computevectors)(pep);
39: }
40: break;
41: default: 42: break;
43: }
44: pep->state = PEP_STATE_EIGENVECTORS;
45: return(0);
46: }
50: PetscErrorCode PEPExtractVectors(PEP pep) 51: {
55: PEPCheckSolved(pep,1);
56: switch (pep->state) {
57: case PEP_STATE_SOLVED:
58: if (pep->ops->extractvectors) {
59: (*pep->ops->extractvectors)(pep);
60: }
61: break;
62: default: 63: break;
64: }
65: return(0);
66: }
70: /*@
71: PEPSolve - Solves the polynomial eigensystem.
73: Collective on PEP 75: Input Parameter:
76: . pep - eigensolver context obtained from PEPCreate()
78: Options Database Keys:
79: + -pep_view - print information about the solver used
80: . -pep_view_matk binary - save any of the coefficient matrices (Ak) to the
81: default binary viewer (replace k by an integer from 0 to nmat-1)
82: . -pep_view_vectors binary - save the computed eigenvectors to the default binary viewer
83: . -pep_view_values - print computed eigenvalues
84: . -pep_converged_reason - print reason for convergence, and number of iterations
85: . -pep_error_absolute - print absolute errors of each eigenpair
86: . -pep_error_relative - print relative errors of each eigenpair
87: - -pep_error_backward - print backward errors of each eigenpair
89: Level: beginner
91: .seealso: PEPCreate(), PEPSetUp(), PEPDestroy(), PEPSetTolerances()
92: @*/
93: PetscErrorCode PEPSolve(PEP pep) 94: {
96: PetscInt i,k;
97: PetscBool flg,islinear;
98: #define OPTLEN 16 99: char str[OPTLEN];
103: if (pep->state>=PEP_STATE_SOLVED) return(0);
104: PetscLogEventBegin(PEP_Solve,pep,0,0,0);
106: /* call setup */
107: PEPSetUp(pep);
108: pep->nconv = 0;
109: pep->its = 0;
110: k = pep->lineariz? pep->ncv: pep->ncv*(pep->nmat-1);
111: for (i=0;i<k;i++) {
112: pep->eigr[i] = 0.0;
113: pep->eigi[i] = 0.0;
114: pep->errest[i] = 0.0;
115: pep->perm[i] = i;
116: }
117: PEPViewFromOptions(pep,NULL,"-pep_view_pre");
119: (*pep->ops->solve)(pep);
120: 121: if (!pep->reason) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_PLIB,"Internal error, solver returned without setting converged reason");
123: PetscObjectTypeCompare((PetscObject)pep,PEPLINEAR,&islinear);
124: if (!islinear) {
125: STPostSolve(pep->st);
126: /* Map eigenvalues back to the original problem */
127: STGetTransform(pep->st,&flg);
128: if (flg && pep->ops->backtransform) {
129: (*pep->ops->backtransform)(pep);
130: }
131: }
133: pep->state = PEP_STATE_SOLVED;
135: #if !defined(PETSC_USE_COMPLEX)
136: /* reorder conjugate eigenvalues (positive imaginary first) */
137: for (i=0;i<pep->nconv-1;i++) {
138: if (pep->eigi[i] != 0) {
139: if (pep->eigi[i] < 0) {
140: pep->eigi[i] = -pep->eigi[i];
141: pep->eigi[i+1] = -pep->eigi[i+1];
142: /* the next correction only works with eigenvectors */
143: PEPComputeVectors(pep);
144: BVScaleColumn(pep->V,i+1,-1.0);
145: }
146: i++;
147: }
148: }
149: #endif
151: if (pep->refine==PEP_REFINE_SIMPLE && pep->rits>0 && pep->nconv>0) {
152: PEPComputeVectors(pep);
153: PEPNewtonRefinementSimple(pep,&pep->rits,pep->rtol,pep->nconv);
154: }
156: /* sort eigenvalues according to pep->which parameter */
157: SlepcSortEigenvalues(pep->sc,pep->nconv,pep->eigr,pep->eigi,pep->perm);
158: PetscLogEventEnd(PEP_Solve,pep,0,0,0);
160: /* various viewers */
161: PEPViewFromOptions(pep,NULL,"-pep_view");
162: PEPReasonViewFromOptions(pep);
163: PEPErrorViewFromOptions(pep);
164: PEPValuesViewFromOptions(pep);
165: PEPVectorsViewFromOptions(pep);
166: for (i=0;i<pep->nmat;i++) {
167: PetscSNPrintf(str,OPTLEN,"-pep_view_mat%d",(int)i);
168: MatViewFromOptions(pep->A[i],(PetscObject)pep,str);
169: }
171: /* Remove the initial subspace */
172: pep->nini = 0;
173: return(0);
174: }
178: /*@
179: PEPGetIterationNumber - Gets the current iteration number. If the
180: call to PEPSolve() is complete, then it returns the number of iterations
181: carried out by the solution method.
183: Not Collective
185: Input Parameter:
186: . pep - the polynomial eigensolver context
188: Output Parameter:
189: . its - number of iterations
191: Level: intermediate
193: Note:
194: During the i-th iteration this call returns i-1. If PEPSolve() is
195: complete, then parameter "its" contains either the iteration number at
196: which convergence was successfully reached, or failure was detected.
197: Call PEPGetConvergedReason() to determine if the solver converged or
198: failed and why.
200: .seealso: PEPGetConvergedReason(), PEPSetTolerances()
201: @*/
202: PetscErrorCode PEPGetIterationNumber(PEP pep,PetscInt *its)203: {
207: *its = pep->its;
208: return(0);
209: }
213: /*@
214: PEPGetConverged - Gets the number of converged eigenpairs.
216: Not Collective
218: Input Parameter:
219: . pep - the polynomial eigensolver context
221: Output Parameter:
222: . nconv - number of converged eigenpairs
224: Note:
225: This function should be called after PEPSolve() has finished.
227: Level: beginner
229: .seealso: PEPSetDimensions(), PEPSolve()
230: @*/
231: PetscErrorCode PEPGetConverged(PEP pep,PetscInt *nconv)232: {
236: PEPCheckSolved(pep,1);
237: *nconv = pep->nconv;
238: return(0);
239: }
243: /*@
244: PEPGetConvergedReason - Gets the reason why the PEPSolve() iteration was
245: stopped.
247: Not Collective
249: Input Parameter:
250: . pep - the polynomial eigensolver context
252: Output Parameter:
253: . reason - negative value indicates diverged, positive value converged
255: Possible values for reason:
256: + PEP_CONVERGED_TOL - converged up to tolerance
257: . PEP_CONVERGED_USER - converged due to a user-defined condition
258: . PEP_DIVERGED_ITS - required more than max_it iterations to reach convergence
259: . PEP_DIVERGED_BREAKDOWN - generic breakdown in method
260: - PEP_DIVERGED_SYMMETRY_LOST - pseudo-Lanczos was not able to keep symmetry
262: Note:
263: Can only be called after the call to PEPSolve() is complete.
265: Level: intermediate
267: .seealso: PEPSetTolerances(), PEPSolve(), PEPConvergedReason268: @*/
269: PetscErrorCode PEPGetConvergedReason(PEP pep,PEPConvergedReason *reason)270: {
274: PEPCheckSolved(pep,1);
275: *reason = pep->reason;
276: return(0);
277: }
281: /*@
282: PEPGetEigenpair - Gets the i-th solution of the eigenproblem as computed by
283: PEPSolve(). The solution consists in both the eigenvalue and the eigenvector.
285: Logically Collective on EPS287: Input Parameters:
288: + pep - polynomial eigensolver context
289: - i - index of the solution
291: Output Parameters:
292: + eigr - real part of eigenvalue
293: . eigi - imaginary part of eigenvalue
294: . Vr - real part of eigenvector
295: - Vi - imaginary part of eigenvector
297: Notes:
298: It is allowed to pass NULL for Vr and Vi, if the eigenvector is not
299: required. Otherwise, the caller must provide valid Vec objects, i.e.,
300: they must be created by the calling program with e.g. MatCreateVecs().
302: If the eigenvalue is real, then eigi and Vi are set to zero. If PETSc is
303: configured with complex scalars the eigenvalue is stored
304: directly in eigr (eigi is set to zero) and the eigenvector in Vr (Vi is
305: set to zero). In both cases, the user can pass NULL in eigi and Vi.
307: The index i should be a value between 0 and nconv-1 (see PEPGetConverged()).
308: Eigenpairs are indexed according to the ordering criterion established
309: with PEPSetWhichEigenpairs().
311: Level: beginner
313: .seealso: PEPSolve(), PEPGetConverged(), PEPSetWhichEigenpairs()
314: @*/
315: PetscErrorCode PEPGetEigenpair(PEP pep,PetscInt i,PetscScalar *eigr,PetscScalar *eigi,Vec Vr,Vec Vi)316: {
317: PetscInt k;
325: PEPCheckSolved(pep,1);
326: if (i<0 || i>=pep->nconv) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
328: PEPComputeVectors(pep);
329: k = pep->perm[i];
331: /* eigenvalue */
332: #if defined(PETSC_USE_COMPLEX)
333: if (eigr) *eigr = pep->eigr[k];
334: if (eigi) *eigi = 0;
335: #else
336: if (eigr) *eigr = pep->eigr[k];
337: if (eigi) *eigi = pep->eigi[k];
338: #endif
340: /* eigenvector */
341: #if defined(PETSC_USE_COMPLEX)
342: if (Vr) { BVCopyVec(pep->V,k,Vr); }
343: if (Vi) { VecSet(Vi,0.0); }
344: #else
345: if (pep->eigi[k]>0) { /* first value of conjugate pair */
346: if (Vr) { BVCopyVec(pep->V,k,Vr); }
347: if (Vi) { BVCopyVec(pep->V,k+1,Vi); }
348: } else if (pep->eigi[k]<0) { /* second value of conjugate pair */
349: if (Vr) { BVCopyVec(pep->V,k-1,Vr); }
350: if (Vi) {
351: BVCopyVec(pep->V,k,Vi);
352: VecScale(Vi,-1.0);
353: }
354: } else { /* real eigenvalue */
355: if (Vr) { BVCopyVec(pep->V,k,Vr); }
356: if (Vi) { VecSet(Vi,0.0); }
357: }
358: #endif
359: return(0);
360: }
364: /*@
365: PEPGetErrorEstimate - Returns the error estimate associated to the i-th
366: computed eigenpair.
368: Not Collective
370: Input Parameter:
371: + pep - polynomial eigensolver context
372: - i - index of eigenpair
374: Output Parameter:
375: . errest - the error estimate
377: Notes:
378: This is the error estimate used internally by the eigensolver. The actual
379: error bound can be computed with PEPComputeError(). See also the users
380: manual for details.
382: Level: advanced
384: .seealso: PEPComputeError()
385: @*/
386: PetscErrorCode PEPGetErrorEstimate(PEP pep,PetscInt i,PetscReal *errest)387: {
391: PEPCheckSolved(pep,1);
392: if (i<0 || i>=pep->nconv) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
393: if (errest) *errest = pep->errest[pep->perm[i]];
394: return(0);
395: }
399: /*
400: PEPComputeResidualNorm_Private - Computes the norm of the residual vector
401: associated with an eigenpair.
403: Input Parameters:
404: kr,ki - eigenvalue
405: xr,xi - eigenvector
406: z - array of 4 work vectors (z[2],z[3] not referenced in complex scalars)
407: */
408: PetscErrorCode PEPComputeResidualNorm_Private(PEP pep,PetscScalar kr,PetscScalar ki,Vec xr,Vec xi,Vec *z,PetscReal *norm)409: {
411: Mat *A=pep->A;
412: PetscInt i,nmat=pep->nmat;
413: PetscScalar t[20],*vals=t,*ivals=NULL;
414: Vec u,w;
415: #if !defined(PETSC_USE_COMPLEX)
416: Vec ui,wi;
417: PetscReal ni;
418: PetscBool imag;
419: PetscScalar it[20];
420: #endif
423: u = z[0]; w = z[1];
424: VecSet(u,0.0);
425: #if !defined(PETSC_USE_COMPLEX)
426: ui = z[2]; wi = z[3];
427: ivals = it;
428: #endif
429: if (nmat>20) {
430: PetscMalloc(nmat*sizeof(PetscScalar),&vals);
431: #if !defined(PETSC_USE_COMPLEX)
432: PetscMalloc(nmat*sizeof(PetscScalar),&ivals);
433: #endif
434: }
435: PEPEvaluateBasis(pep,kr,ki,vals,ivals);
436: #if !defined(PETSC_USE_COMPLEX)
437: if (ki == 0 || PetscAbsScalar(ki) < PetscAbsScalar(kr*PETSC_MACHINE_EPSILON))
438: imag = PETSC_FALSE;
439: else {
440: imag = PETSC_TRUE;
441: VecSet(ui,0.0);
442: }
443: #endif
444: for (i=0;i<nmat;i++) {
445: if (vals[i]!=0.0) {
446: MatMult(A[i],xr,w);
447: VecAXPY(u,vals[i],w);
448: }
449: #if !defined(PETSC_USE_COMPLEX)
450: if (imag) {
451: if (ivals[i]!=0 || vals[i]!=0) {
452: MatMult(A[i],xi,wi);
453: if (vals[i]==0) {
454: MatMult(A[i],xr,w);
455: }
456: }
457: if (ivals[i]!=0){
458: VecAXPY(u,-ivals[i],wi);
459: VecAXPY(ui,ivals[i],w);
460: }
461: if (vals[i]!=0) {
462: VecAXPY(ui,vals[i],wi);
463: }
464: }
465: #endif
466: }
467: VecNorm(u,NORM_2,norm);
468: #if !defined(PETSC_USE_COMPLEX)
469: if (imag) {
470: VecNorm(ui,NORM_2,&ni);
471: *norm = SlepcAbsEigenvalue(*norm,ni);
472: }
473: #endif
474: if (nmat>20) {
475: PetscFree(vals);
476: #if !defined(PETSC_USE_COMPLEX)
477: PetscFree(ivals);
478: #endif
479: }
480: return(0);
481: }
485: /*@
486: PEPComputeError - Computes the error (based on the residual norm) associated
487: with the i-th computed eigenpair.
489: Collective on PEP491: Input Parameter:
492: + pep - the polynomial eigensolver context
493: . i - the solution index
494: - type - the type of error to compute
496: Output Parameter:
497: . error - the error
499: Notes:
500: The error can be computed in various ways, all of them based on the residual
501: norm ||P(l)x||_2 where l is the eigenvalue and x is the eigenvector.
502: See the users guide for additional details.
504: Level: beginner
506: .seealso: PEPErrorType, PEPSolve(), PEPGetErrorEstimate()
507: @*/
508: PetscErrorCode PEPComputeError(PEP pep,PetscInt i,PEPErrorType type,PetscReal *error)509: {
511: Vec xr,xi,w[4];
512: PetscScalar kr,ki;
513: PetscReal t,z=0.0;
514: PetscInt j;
515: PetscBool flg;
522: PEPCheckSolved(pep,1);
524: /* allocate work vectors */
525: #if defined(PETSC_USE_COMPLEX)
526: PEPSetWorkVecs(pep,3);
527: xi = NULL;
528: w[2] = NULL;
529: w[3] = NULL;
530: #else
531: PEPSetWorkVecs(pep,6);
532: xi = pep->work[3];
533: w[2] = pep->work[4];
534: w[3] = pep->work[5];
535: #endif
536: xr = pep->work[0];
537: w[0] = pep->work[1];
538: w[1] = pep->work[2];
540: /* compute residual norms */
541: PEPGetEigenpair(pep,i,&kr,&ki,xr,xi);
542: PEPComputeResidualNorm_Private(pep,kr,ki,xr,xi,w,error);
544: /* compute error */
545: switch (type) {
546: case PEP_ERROR_ABSOLUTE:
547: break;
548: case PEP_ERROR_RELATIVE:
549: *error /= SlepcAbsEigenvalue(kr,ki);
550: break;
551: case PEP_ERROR_BACKWARD:
552: /* initialization of matrix norms */
553: if (!pep->nrma[pep->nmat-1]) {
554: for (j=0;j<pep->nmat;j++) {
555: MatHasOperation(pep->A[j],MATOP_NORM,&flg);
556: if (!flg) SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_ARG_WRONG,"The computation of backward errors requires a matrix norm operation");
557: MatNorm(pep->A[j],NORM_INFINITY,&pep->nrma[j]);
558: }
559: }
560: t = SlepcAbsEigenvalue(kr,ki);
561: for (j=pep->nmat-1;j>=0;j--) {
562: z = z*t+pep->nrma[j];
563: }
564: *error /= z;
565: break;
566: default:567: SETERRQ(PetscObjectComm((PetscObject)pep),PETSC_ERR_ARG_OUTOFRANGE,"Invalid error type");
568: }
569: return(0);
570: }