Actual source code: qepsolve.c

  1: /*
  2:       QEP routines related to the solution process.

  4:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  5:    SLEPc - Scalable Library for Eigenvalue Problem Computations
  6:    Copyright (c) 2002-2013, Universitat Politecnica de Valencia, Spain

  8:    This file is part of SLEPc.

 10:    SLEPc is free software: you can redistribute it and/or modify it under  the
 11:    terms of version 3 of the GNU Lesser General Public License as published by
 12:    the Free Software Foundation.

 14:    SLEPc  is  distributed in the hope that it will be useful, but WITHOUT  ANY
 15:    WARRANTY;  without even the implied warranty of MERCHANTABILITY or  FITNESS
 16:    FOR  A  PARTICULAR PURPOSE. See the GNU Lesser General Public  License  for
 17:    more details.

 19:    You  should have received a copy of the GNU Lesser General  Public  License
 20:    along with SLEPc. If not, see <http://www.gnu.org/licenses/>.
 21:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 22: */

 24: #include <slepc-private/qepimpl.h>       /*I "slepcqep.h" I*/
 25: #include <petscdraw.h>

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

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

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

 50: /*@
 51:    QEPSolve - Solves the quadratic eigensystem.

 53:    Collective on QEP

 55:    Input Parameter:
 56: .  qep - eigensolver context obtained from QEPCreate()

 58:    Options Database Keys:
 59: +  -qep_view - print information about the solver used
 60: .  -qep_view_mat0 binary - save the first matrix (M) to the default binary viewer
 61: .  -qep_view_mat1 binary - save the second matrix (C) to the default binary viewer
 62: .  -qep_view_mat2 binary - save the third matrix (K) to the default binary viewer
 63: -  -qep_plot_eigs - plot computed eigenvalues

 65:    Level: beginner

 67: .seealso: QEPCreate(), QEPSetUp(), QEPDestroy(), QEPSetTolerances()
 68: @*/
 69: PetscErrorCode QEPSolve(QEP qep)
 70: {
 71:   PetscErrorCode    ierr;
 72:   PetscInt          i;
 73:   PetscReal         re,im;
 74:   PetscBool         flg,islinear;
 75:   PetscViewer       viewer;
 76:   PetscViewerFormat format;
 77:   PetscDraw         draw;
 78:   PetscDrawSP       drawsp;
 79:   QEPSortForSTData  data;

 83:   PetscLogEventBegin(QEP_Solve,qep,0,0,0);

 85:   /* call setup */
 86:   QEPSetUp(qep);
 87:   qep->nconv = 0;
 88:   qep->its   = 0;
 89:   for (i=0;i<qep->ncv;i++) {
 90:     qep->eigr[i]   = 0.0;
 91:     qep->eigi[i]   = 0.0;
 92:     qep->errest[i] = 0.0;
 93:   }
 94:   QEPMonitor(qep,qep->its,qep->nconv,qep->eigr,qep->eigi,qep->errest,qep->ncv);

 96:   PetscObjectTypeCompare((PetscObject)qep,QEPLINEAR,&islinear);
 97:   if (!islinear) {
 98:     /* temporarily change eigenvalue comparison function */
 99:     data.comparison    = qep->comparison;
100:     data.comparisonctx = qep->comparisonctx;
101:     data.st            = qep->st;
102:     qep->comparison    = QEPSortForSTFunc;
103:     qep->comparisonctx = &data;
104:   }
105:   DSSetEigenvalueComparison(qep->ds,qep->comparison,qep->comparisonctx);

107:   (*qep->ops->solve)(qep);
108:   if (!islinear) {
109:     STPostSolve(qep->st);
110:   }

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

114:   if (!islinear) {
115:     /* restore comparison function */
116:     qep->comparison    = data.comparison;
117:     qep->comparisonctx = data.comparisonctx;
118:     /* Map eigenvalues back to the original problem */
119:     STBackTransform(qep->st,qep->nconv,qep->eigr,qep->eigi);
120:   }

122: #if !defined(PETSC_USE_COMPLEX)
123:   /* reorder conjugate eigenvalues (positive imaginary first) */
124:   for (i=0;i<qep->nconv-1;i++) {
125:     if (qep->eigi[i] != 0) {
126:       if (qep->eigi[i] < 0) {
127:         qep->eigi[i] = -qep->eigi[i];
128:         qep->eigi[i+1] = -qep->eigi[i+1];
129:         VecScale(qep->V[i+1],-1.0);
130:       }
131:       i++;
132:     }
133:   }
134: #endif

136:   /* sort eigenvalues according to qep->which parameter */
137:   QEPSortEigenvalues(qep,qep->nconv,qep->eigr,qep->eigi,qep->perm);

139:   PetscLogEventEnd(QEP_Solve,qep,0,0,0);

141:   /* various viewers */
142:   MatViewFromOptions(qep->M,((PetscObject)qep)->prefix,"-qep_view_mat0");
143:   MatViewFromOptions(qep->C,((PetscObject)qep)->prefix,"-qep_view_mat1");
144:   MatViewFromOptions(qep->K,((PetscObject)qep)->prefix,"-qep_view_mat2");

146:   PetscOptionsGetViewer(PetscObjectComm((PetscObject)qep),((PetscObject)qep)->prefix,"-qep_view",&viewer,&format,&flg);
147:   if (flg && !PetscPreLoadingOn) {
148:     PetscViewerPushFormat(viewer,format);
149:     QEPView(qep,viewer);
150:     PetscViewerPopFormat(viewer);
151:     PetscViewerDestroy(&viewer);
152:   }

154:   flg = PETSC_FALSE;
155:   PetscOptionsGetBool(((PetscObject)qep)->prefix,"-qep_plot_eigs",&flg,NULL);
156:   if (flg) {
157:     PetscViewerDrawOpen(PETSC_COMM_SELF,0,"Computed Eigenvalues",PETSC_DECIDE,PETSC_DECIDE,300,300,&viewer);
158:     PetscViewerDrawGetDraw(viewer,0,&draw);
159:     PetscDrawSPCreate(draw,1,&drawsp);
160:     for (i=0;i<qep->nconv;i++) {
161: #if defined(PETSC_USE_COMPLEX)
162:       re = PetscRealPart(qep->eigr[i]);
163:       im = PetscImaginaryPart(qep->eigi[i]);
164: #else
165:       re = qep->eigr[i];
166:       im = qep->eigi[i];
167: #endif
168:       PetscDrawSPAddPoint(drawsp,&re,&im);
169:     }
170:     PetscDrawSPDraw(drawsp,PETSC_TRUE);
171:     PetscDrawSPDestroy(&drawsp);
172:     PetscViewerDestroy(&viewer);
173:   }

175:   /* Remove the initial subspace */
176:   qep->nini = 0;
177:   return(0);
178: }

182: /*@
183:    QEPGetIterationNumber - Gets the current iteration number. If the
184:    call to QEPSolve() is complete, then it returns the number of iterations
185:    carried out by the solution method.

187:    Not Collective

189:    Input Parameter:
190: .  qep - the quadratic eigensolver context

192:    Output Parameter:
193: .  its - number of iterations

195:    Level: intermediate

197:    Note:
198:    During the i-th iteration this call returns i-1. If QEPSolve() is
199:    complete, then parameter "its" contains either the iteration number at
200:    which convergence was successfully reached, or failure was detected.
201:    Call QEPGetConvergedReason() to determine if the solver converged or
202:    failed and why.

204: .seealso: QEPGetConvergedReason(), QEPSetTolerances()
205: @*/
206: PetscErrorCode QEPGetIterationNumber(QEP qep,PetscInt *its)
207: {
211:   *its = qep->its;
212:   return(0);
213: }

217: /*@
218:    QEPGetConverged - Gets the number of converged eigenpairs.

220:    Not Collective

222:    Input Parameter:
223: .  qep - the quadratic eigensolver context

225:    Output Parameter:
226: .  nconv - number of converged eigenpairs

228:    Note:
229:    This function should be called after QEPSolve() has finished.

231:    Level: beginner

233: .seealso: QEPSetDimensions(), QEPSolve()
234: @*/
235: PetscErrorCode QEPGetConverged(QEP qep,PetscInt *nconv)
236: {
240:   *nconv = qep->nconv;
241:   return(0);
242: }

246: /*@C
247:    QEPGetConvergedReason - Gets the reason why the QEPSolve() iteration was
248:    stopped.

250:    Not Collective

252:    Input Parameter:
253: .  qep - the quadratic eigensolver context

255:    Output Parameter:
256: .  reason - negative value indicates diverged, positive value converged

258:    Possible values for reason:
259: +  QEP_CONVERGED_TOL - converged up to tolerance
260: .  QEP_DIVERGED_ITS - required more than its to reach convergence
261: -  QEP_DIVERGED_BREAKDOWN - generic breakdown in method

263:    Note:
264:    Can only be called after the call to QEPSolve() is complete.

266:    Level: intermediate

268: .seealso: QEPSetTolerances(), QEPSolve(), QEPConvergedReason
269: @*/
270: PetscErrorCode QEPGetConvergedReason(QEP qep,QEPConvergedReason *reason)
271: {
275:   *reason = qep->reason;
276:   return(0);
277: }

281: /*@
282:    QEPGetEigenpair - Gets the i-th solution of the eigenproblem as computed by
283:    QEPSolve(). The solution consists in both the eigenvalue and the eigenvector.

285:    Logically Collective on EPS

287:    Input Parameters:
288: +  qep - quadratic 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:    If the eigenvalue is real, then eigi and Vi are set to zero. If PETSc is
299:    configured with complex scalars the eigenvalue is stored
300:    directly in eigr (eigi is set to zero) and the eigenvector in Vr (Vi is
301:    set to zero).

303:    The index i should be a value between 0 and nconv-1 (see QEPGetConverged()).
304:    Eigenpairs are indexed according to the ordering criterion established
305:    with QEPSetWhichEigenpairs().

307:    Level: beginner

309: .seealso: QEPSolve(), QEPGetConverged(), QEPSetWhichEigenpairs()
310: @*/
311: PetscErrorCode QEPGetEigenpair(QEP qep,PetscInt i,PetscScalar *eigr,PetscScalar *eigi,Vec Vr,Vec Vi)
312: {
313:   PetscInt       k;

321:   if (!qep->eigr || !qep->eigi || !qep->V) SETERRQ(PetscObjectComm((PetscObject)qep),PETSC_ERR_ARG_WRONGSTATE,"QEPSolve must be called first");
322:   if (i<0 || i>=qep->nconv) SETERRQ(PetscObjectComm((PetscObject)qep),PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");

324:   if (!qep->perm) k = i;
325:   else k = qep->perm[i];

327:   /* eigenvalue */
328: #if defined(PETSC_USE_COMPLEX)
329:   if (eigr) *eigr = qep->eigr[k];
330:   if (eigi) *eigi = 0;
331: #else
332:   if (eigr) *eigr = qep->eigr[k];
333:   if (eigi) *eigi = qep->eigi[k];
334: #endif

336:   /* eigenvector */
337: #if defined(PETSC_USE_COMPLEX)
338:   if (Vr) { VecCopy(qep->V[k],Vr); }
339:   if (Vi) { VecSet(Vi,0.0); }
340: #else
341:   if (qep->eigi[k]>0) { /* first value of conjugate pair */
342:     if (Vr) { VecCopy(qep->V[k],Vr); }
343:     if (Vi) { VecCopy(qep->V[k+1],Vi); }
344:   } else if (qep->eigi[k]<0) { /* second value of conjugate pair */
345:     if (Vr) { VecCopy(qep->V[k-1],Vr); }
346:     if (Vi) {
347:       VecCopy(qep->V[k],Vi);
348:       VecScale(Vi,-1.0);
349:     }
350:   } else { /* real eigenvalue */
351:     if (Vr) { VecCopy(qep->V[k],Vr); }
352:     if (Vi) { VecSet(Vi,0.0); }
353:   }
354: #endif
355:   return(0);
356: }

360: /*@
361:    QEPGetErrorEstimate - Returns the error estimate associated to the i-th
362:    computed eigenpair.

364:    Not Collective

366:    Input Parameter:
367: +  qep - quadratic eigensolver context
368: -  i   - index of eigenpair

370:    Output Parameter:
371: .  errest - the error estimate

373:    Notes:
374:    This is the error estimate used internally by the eigensolver. The actual
375:    error bound can be computed with QEPComputeRelativeError(). See also the users
376:    manual for details.

378:    Level: advanced

380: .seealso: QEPComputeRelativeError()
381: @*/
382: PetscErrorCode QEPGetErrorEstimate(QEP qep,PetscInt i,PetscReal *errest)
383: {
387:   if (!qep->eigr || !qep->eigi) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"QEPSolve must be called first");
388:   if (i<0 || i>=qep->nconv) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Argument 2 out of range");
389:   if (qep->perm) i = qep->perm[i];
390:   if (errest) *errest = qep->errest[i];
391:   return(0);
392: }

396: /*
397:    QEPComputeResidualNorm_Private - Computes the norm of the residual vector
398:    associated with an eigenpair.
399: */
400: PetscErrorCode QEPComputeResidualNorm_Private(QEP qep,PetscScalar kr,PetscScalar ki,Vec xr,Vec xi,PetscReal *norm)
401: {
403:   Vec            u,w;
404:   Mat            M=qep->M,C=qep->C,K=qep->K;
405: #if !defined(PETSC_USE_COMPLEX)
406:   Vec            v,y,z;
407:   PetscReal      ni,nr;
408:   PetscScalar    a1,a2;
409: #endif

412:   VecDuplicate(qep->V[0],&u);
413:   VecDuplicate(u,&w);

415: #if !defined(PETSC_USE_COMPLEX)
416:   if (ki == 0 || PetscAbsScalar(ki) < PetscAbsScalar(kr*PETSC_MACHINE_EPSILON)) {
417: #endif
418:     MatMult(K,xr,u);                 /* u=K*x */
419:     if (PetscAbsScalar(kr) > PETSC_MACHINE_EPSILON) {
420:       MatMult(C,xr,w);               /* w=C*x */
421:       VecAXPY(u,kr,w);               /* u=l*C*x+K*x */
422:       MatMult(M,xr,w);               /* w=M*x */
423:       VecAXPY(u,kr*kr,w);            /* u=l^2*M*x+l*C*x+K*x */
424:     }
425:     VecNorm(u,NORM_2,norm);
426: #if !defined(PETSC_USE_COMPLEX)
427:   } else {
428:     VecDuplicate(u,&v);
429:     VecDuplicate(u,&y);
430:     VecDuplicate(u,&z);
431:     a1 = kr*kr-ki*ki;
432:     a2 = 2.0*kr*ki;
433:     MatMult(K,xr,u);           /* u=K*xr */
434:     if (SlepcAbsEigenvalue(kr,ki) > PETSC_MACHINE_EPSILON) {
435:       MatMult(C,xr,v);         /* v=C*xr */
436:       MatMult(C,xi,w);         /* w=C*xi */
437:       MatMult(M,xr,y);         /* y=M*xr */
438:       MatMult(M,xi,z);         /* z=M*xi */
439:       VecAXPY(u,kr,v);         /* u=kr*C*xr+K*xr */
440:       VecAXPY(u,-ki,w);        /* u=kr*C*xr-ki*C*xi+K*xr */
441:       VecAXPY(u,a1,y);         /* u=a1*M*xr+kr*C*xr-ki*C*xi+K*xr */
442:       VecAXPY(u,-a2,z);        /* u=a1*M*xr-a2*M*xi+kr*C*xr-ki*C*xi+K*xr */
443:     }
444:     VecNorm(u,NORM_2,&nr);
445:     MatMult(K,xi,u);         /* u=K*xi */
446:     if (SlepcAbsEigenvalue(kr,ki) > PETSC_MACHINE_EPSILON) {
447:       VecAXPY(u,kr,w);         /* u=kr*C*xi+K*xi */
448:       VecAXPY(u,ki,v);         /* u=kr*C*xi+ki*C*xi+K*xi */
449:       VecAXPY(u,a1,z);         /* u=a1*M*xi+kr*C*xi+ki*C*xi+K*xi */
450:       VecAXPY(u,a2,y);         /* u=a1*M*xi+a2*M*ki+kr*C*xi+ki*C*xi+K*xi */
451:     }
452:     VecNorm(u,NORM_2,&ni);
453:     *norm = SlepcAbsEigenvalue(nr,ni);
454:     VecDestroy(&v);
455:     VecDestroy(&y);
456:     VecDestroy(&z);
457:   }
458: #endif

460:   VecDestroy(&w);
461:   VecDestroy(&u);
462:   return(0);
463: }

467: /*@
468:    QEPComputeResidualNorm - Computes the norm of the residual vector associated with
469:    the i-th computed eigenpair.

471:    Collective on QEP

473:    Input Parameter:
474: +  qep - the quadratic eigensolver context
475: -  i   - the solution index

477:    Output Parameter:
478: .  norm - the residual norm, computed as ||(l^2*M+l*C+K)x||_2 where l is the
479:    eigenvalue and x is the eigenvector.
480:    If l=0 then the residual norm is computed as ||Kx||_2.

482:    Notes:
483:    The index i should be a value between 0 and nconv-1 (see QEPGetConverged()).
484:    Eigenpairs are indexed according to the ordering criterion established
485:    with QEPSetWhichEigenpairs().

487:    Level: beginner

489: .seealso: QEPSolve(), QEPGetConverged(), QEPSetWhichEigenpairs()
490: @*/
491: PetscErrorCode QEPComputeResidualNorm(QEP qep,PetscInt i,PetscReal *norm)
492: {
494:   Vec            xr,xi;
495:   PetscScalar    kr,ki;

501:   VecDuplicate(qep->V[0],&xr);
502:   VecDuplicate(qep->V[0],&xi);
503:   QEPGetEigenpair(qep,i,&kr,&ki,xr,xi);
504:   QEPComputeResidualNorm_Private(qep,kr,ki,xr,xi,norm);
505:   VecDestroy(&xr);
506:   VecDestroy(&xi);
507:   return(0);
508: }

512: /*
513:    QEPComputeRelativeError_Private - Computes the relative error bound
514:    associated with an eigenpair.
515: */
516: PetscErrorCode QEPComputeRelativeError_Private(QEP qep,PetscScalar kr,PetscScalar ki,Vec xr,Vec xi,PetscReal *error)
517: {
519:   PetscReal      norm,er;
520: #if !defined(PETSC_USE_COMPLEX)
521:   PetscReal      ei;
522: #endif

525:   QEPComputeResidualNorm_Private(qep,kr,ki,xr,xi,&norm);
526: #if !defined(PETSC_USE_COMPLEX)
527:   if (ki == 0 || PetscAbsScalar(ki) < PetscAbsScalar(kr*PETSC_MACHINE_EPSILON)) {
528: #endif
529:     VecNorm(xr,NORM_2,&er);
530:     if (PetscAbsScalar(kr) > norm) {
531:       *error = norm/(PetscAbsScalar(kr)*er);
532:     } else {
533:       *error = norm/er;
534:     }
535: #if !defined(PETSC_USE_COMPLEX)
536:   } else {
537:     VecNorm(xr,NORM_2,&er);
538:     VecNorm(xi,NORM_2,&ei);
539:     if (SlepcAbsEigenvalue(kr,ki) > norm) {
540:       *error = norm/(SlepcAbsEigenvalue(kr,ki)*SlepcAbsEigenvalue(er,ei));
541:     } else {
542:       *error = norm/SlepcAbsEigenvalue(er,ei);
543:     }
544:   }
545: #endif
546:   return(0);
547: }

551: /*@
552:    QEPComputeRelativeError - Computes the relative error bound associated
553:    with the i-th computed eigenpair.

555:    Collective on QEP

557:    Input Parameter:
558: +  qep - the quadratic eigensolver context
559: -  i   - the solution index

561:    Output Parameter:
562: .  error - the relative error bound, computed as ||(l^2*M+l*C+K)x||_2/||lx||_2 where
563:    l is the eigenvalue and x is the eigenvector.
564:    If l=0 the relative error is computed as ||Kx||_2/||x||_2.

566:    Level: beginner

568: .seealso: QEPSolve(), QEPComputeResidualNorm(), QEPGetErrorEstimate()
569: @*/
570: PetscErrorCode QEPComputeRelativeError(QEP qep,PetscInt i,PetscReal *error)
571: {
573:   Vec            xr,xi;
574:   PetscScalar    kr,ki;

580:   VecDuplicate(qep->V[0],&xr);
581:   VecDuplicate(qep->V[0],&xi);
582:   QEPGetEigenpair(qep,i,&kr,&ki,xr,xi);
583:   QEPComputeRelativeError_Private(qep,kr,ki,xr,xi,error);
584:   VecDestroy(&xr);
585:   VecDestroy(&xi);
586:   return(0);
587: }

591: /*@
592:    QEPSortEigenvalues - Sorts a list of eigenvalues according to the criterion
593:    specified via QEPSetWhichEigenpairs().

595:    Not Collective

597:    Input Parameters:
598: +  qep   - the quadratic eigensolver context
599: .  n     - number of eigenvalues in the list
600: .  eigr  - pointer to the array containing the eigenvalues
601: -  eigi  - imaginary part of the eigenvalues (only when using real numbers)

603:    Output Parameter:
604: .  perm  - resulting permutation

606:    Note:
607:    The result is a list of indices in the original eigenvalue array
608:    corresponding to the first nev eigenvalues sorted in the specified
609:    criterion.

611:    Level: developer

613: .seealso: QEPSetWhichEigenpairs()
614: @*/
615: PetscErrorCode QEPSortEigenvalues(QEP qep,PetscInt n,PetscScalar *eigr,PetscScalar *eigi,PetscInt *perm)
616: {
618:   PetscScalar    re,im;
619:   PetscInt       i,j,result,tmp;

626:   for (i=0;i<n;i++) perm[i] = i;
627:   /* insertion sort */
628:   for (i=n-1; i>=0; i--) {
629:     re = eigr[perm[i]];
630:     im = eigi[perm[i]];
631:     j = i + 1;
632: #if !defined(PETSC_USE_COMPLEX)
633:     if (im != 0) {
634:       /* complex eigenvalue */
635:       i--;
636:       im = eigi[perm[i]];
637:     }
638: #endif
639:     while (j<n) {
640:       QEPCompareEigenvalues(qep,re,im,eigr[perm[j]],eigi[perm[j]],&result);
641:       if (result < 0) break;
642: #if !defined(PETSC_USE_COMPLEX)
643:       /* keep together every complex conjugated eigenpair */
644:       if (im == 0) {
645:         if (eigi[perm[j]] == 0) {
646: #endif
647:           tmp = perm[j-1]; perm[j-1] = perm[j]; perm[j] = tmp;
648:           j++;
649: #if !defined(PETSC_USE_COMPLEX)
650:         } else {
651:           tmp = perm[j-1]; perm[j-1] = perm[j]; perm[j] = perm[j+1]; perm[j+1] = tmp;
652:           j+=2;
653:         }
654:       } else {
655:         if (eigi[perm[j]] == 0) {
656:           tmp = perm[j-2]; perm[j-2] = perm[j]; perm[j] = perm[j-1]; perm[j-1] = tmp;
657:           j++;
658:         } else {
659:           tmp = perm[j-2]; perm[j-2] = perm[j]; perm[j] = tmp;
660:           tmp = perm[j-1]; perm[j-1] = perm[j+1]; perm[j+1] = tmp;
661:           j+=2;
662:         }
663:       }
664: #endif
665:     }
666:   }
667:   return(0);
668: }

672: /*@
673:    QEPCompareEigenvalues - Compares two (possibly complex) eigenvalues according
674:    to a certain criterion.

676:    Not Collective

678:    Input Parameters:
679: +  qep    - the quadratic eigensolver context
680: .  ar     - real part of the 1st eigenvalue
681: .  ai     - imaginary part of the 1st eigenvalue
682: .  br     - real part of the 2nd eigenvalue
683: -  bi     - imaginary part of the 2nd eigenvalue

685:    Output Parameter:
686: .  res    - result of comparison

688:    Notes:
689:    Returns an integer less than, equal to, or greater than zero if the first
690:    eigenvalue is considered to be respectively less than, equal to, or greater
691:    than the second one.

693:    The criterion of comparison is related to the 'which' parameter set with
694:    QEPSetWhichEigenpairs().

696:    Level: developer

698: .seealso: QEPSortEigenvalues(), QEPSetWhichEigenpairs()
699: @*/
700: PetscErrorCode QEPCompareEigenvalues(QEP qep,PetscScalar ar,PetscScalar ai,PetscScalar br,PetscScalar bi,PetscInt *result)
701: {

707:   if (!qep->comparison) SETERRQ(PETSC_COMM_SELF,1,"Undefined eigenvalue comparison function");
708:   (*qep->comparison)(ar,ai,br,bi,result,qep->comparisonctx);
709:   return(0);
710: }

714: /*@
715:    QEPGetOperationCounters - Gets the total number of matrix-vector products, dot
716:    products, and linear solve iterations used by the QEP object during the last
717:    QEPSolve() call.

719:    Not Collective

721:    Input Parameter:
722: .  qep - quadratic eigensolver context

724:    Output Parameter:
725: +  matvecs - number of matrix-vector product operations
726: .  dots    - number of dot product operations
727: -  lits    - number of linear iterations

729:    Notes:
730:    These counters are reset to zero at each successive call to QEPSolve().

732:    Level: intermediate

734: @*/
735: PetscErrorCode QEPGetOperationCounters(QEP qep,PetscInt* matvecs,PetscInt* dots,PetscInt* lits)
736: {

741:   if (matvecs) *matvecs = qep->matvecs;
742:   if (dots) {
743:     if (!qep->ip) { QEPGetIP(qep,&qep->ip); }
744:     IPGetOperationCounters(qep->ip,dots);
745:   }
746:   if (lits) *lits = qep->linits;
747:   return(0);
748: }