LCOV - code coverage report
Current view: top level - eps/impls/lyapii - lyapii.c (source / functions) Hit Total Coverage
Test: SLEPc Lines: 424 444 95.5 %
Date: 2024-12-18 00:51:33 Functions: 21 23 91.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
       3             :    SLEPc - Scalable Library for Eigenvalue Problem Computations
       4             :    Copyright (c) 2002-, Universitat Politecnica de Valencia, Spain
       5             : 
       6             :    This file is part of SLEPc.
       7             :    SLEPc is distributed under a 2-clause BSD license (see LICENSE).
       8             :    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
       9             : */
      10             : /*
      11             :    SLEPc eigensolver: "lyapii"
      12             : 
      13             :    Method: Lyapunov inverse iteration
      14             : 
      15             :    Algorithm:
      16             : 
      17             :        Lyapunov inverse iteration using LME solvers
      18             : 
      19             :    References:
      20             : 
      21             :        [1] H.C. Elman and M. Wu, "Lyapunov inverse iteration for computing a
      22             :            few rightmost eigenvalues of large generalized eigenvalue problems",
      23             :            SIAM J. Matrix Anal. Appl. 34(4):1685-1707, 2013.
      24             : 
      25             :        [2] K. Meerbergen and A. Spence, "Inverse iteration for purely imaginary
      26             :            eigenvalues with application to the detection of Hopf bifurcations in
      27             :            large-scale problems", SIAM J. Matrix Anal. Appl. 31:1982-1999, 2010.
      28             : */
      29             : 
      30             : #include <slepc/private/epsimpl.h>          /*I "slepceps.h" I*/
      31             : #include <slepcblaslapack.h>
      32             : 
      33             : typedef struct {
      34             :   LME      lme;      /* Lyapunov solver */
      35             :   DS       ds;       /* used to compute the SVD for compression */
      36             :   PetscInt rkl;      /* prescribed rank for the Lyapunov solver */
      37             :   PetscInt rkc;      /* the compressed rank, cannot be larger than rkl */
      38             : } EPS_LYAPII;
      39             : 
      40             : typedef struct {
      41             :   Mat      S;        /* the operator matrix, S=A^{-1}*B */
      42             :   BV       Q;        /* orthogonal basis of converged eigenvectors */
      43             : } EPS_LYAPII_MATSHELL;
      44             : 
      45             : typedef struct {
      46             :   Mat      S;        /* the matrix from which the implicit operator is built */
      47             :   PetscInt n;        /* the size of matrix S, the operator is nxn */
      48             :   LME      lme;      /* dummy LME object */
      49             : #if defined(PETSC_USE_COMPLEX)
      50             :   Mat      A,B,F;
      51             :   Vec      w;
      52             : #endif
      53             : } EPS_EIG_MATSHELL;
      54             : 
      55           3 : static PetscErrorCode EPSSetUp_LyapII(EPS eps)
      56             : {
      57           3 :   PetscRandom    rand;
      58           3 :   EPS_LYAPII     *ctx = (EPS_LYAPII*)eps->data;
      59             : 
      60           3 :   PetscFunctionBegin;
      61           3 :   EPSCheckSinvert(eps);
      62           3 :   EPSCheckNotStructured(eps);
      63           3 :   if (eps->nev==0) eps->nev = 1;
      64           3 :   if (eps->ncv!=PETSC_DETERMINE) {
      65           0 :     PetscCheck(eps->ncv>=eps->nev+1,PetscObjectComm((PetscObject)eps),PETSC_ERR_USER_INPUT,"The value of ncv must be at least nev+1");
      66           3 :   } else eps->ncv = eps->nev+1;
      67           3 :   if (eps->mpd!=PETSC_DETERMINE) PetscCall(PetscInfo(eps,"Warning: parameter mpd ignored\n"));
      68           3 :   if (eps->max_it==PETSC_DETERMINE) eps->max_it = PetscMax(1000*eps->nev,100*eps->n);
      69           3 :   if (!eps->which) eps->which=EPS_LARGEST_REAL;
      70           3 :   PetscCheck(eps->which==EPS_LARGEST_REAL,PetscObjectComm((PetscObject)eps),PETSC_ERR_SUP,"This solver supports only largest real eigenvalues");
      71           3 :   EPSCheckUnsupported(eps,EPS_FEATURE_BALANCE | EPS_FEATURE_ARBITRARY | EPS_FEATURE_REGION | EPS_FEATURE_EXTRACTION | EPS_FEATURE_THRESHOLD | EPS_FEATURE_TWOSIDED);
      72             : 
      73           3 :   if (!ctx->rkc) ctx->rkc = 10;
      74           3 :   if (!ctx->rkl) ctx->rkl = 3*ctx->rkc;
      75           3 :   if (!ctx->lme) PetscCall(EPSLyapIIGetLME(eps,&ctx->lme));
      76           3 :   PetscCall(LMESetProblemType(ctx->lme,LME_LYAPUNOV));
      77           3 :   PetscCall(LMESetErrorIfNotConverged(ctx->lme,PETSC_TRUE));
      78             : 
      79           3 :   if (!ctx->ds) {
      80           3 :     PetscCall(DSCreate(PetscObjectComm((PetscObject)eps),&ctx->ds));
      81           3 :     PetscCall(DSSetType(ctx->ds,DSSVD));
      82             :   }
      83           3 :   PetscCall(DSAllocate(ctx->ds,ctx->rkl));
      84             : 
      85           3 :   PetscCall(DSSetType(eps->ds,DSNHEP));
      86           3 :   PetscCall(DSAllocate(eps->ds,eps->ncv));
      87             : 
      88           3 :   PetscCall(EPSAllocateSolution(eps,0));
      89           3 :   PetscCall(BVGetRandomContext(eps->V,&rand));  /* make sure the random context is available when duplicating */
      90           3 :   PetscCall(EPSSetWorkVecs(eps,3));
      91           3 :   PetscFunctionReturn(PETSC_SUCCESS);
      92             : }
      93             : 
      94        3174 : static PetscErrorCode MatMult_EPSLyapIIOperator(Mat M,Vec x,Vec r)
      95             : {
      96        3174 :   EPS_LYAPII_MATSHELL *matctx;
      97             : 
      98        3174 :   PetscFunctionBegin;
      99        3174 :   PetscCall(MatShellGetContext(M,&matctx));
     100        3174 :   PetscCall(MatMult(matctx->S,x,r));
     101        3174 :   PetscCall(BVOrthogonalizeVec(matctx->Q,r,NULL,NULL,NULL));
     102        3174 :   PetscFunctionReturn(PETSC_SUCCESS);
     103             : }
     104             : 
     105           3 : static PetscErrorCode MatDestroy_EPSLyapIIOperator(Mat M)
     106             : {
     107           3 :   EPS_LYAPII_MATSHELL *matctx;
     108             : 
     109           3 :   PetscFunctionBegin;
     110           3 :   PetscCall(MatShellGetContext(M,&matctx));
     111           3 :   PetscCall(MatDestroy(&matctx->S));
     112           3 :   PetscCall(PetscFree(matctx));
     113           3 :   PetscFunctionReturn(PETSC_SUCCESS);
     114             : }
     115             : 
     116         704 : static PetscErrorCode MatMult_EigOperator(Mat M,Vec x,Vec y)
     117             : {
     118         704 :   EPS_EIG_MATSHELL  *matctx;
     119             : #if !defined(PETSC_USE_COMPLEX)
     120             :   PetscInt          n,lds;
     121             :   PetscScalar       *Y,*C,zero=0.0,done=1.0,dtwo=2.0;
     122             :   const PetscScalar *S,*X;
     123             :   PetscBLASInt      n_,lds_;
     124             : #endif
     125             : 
     126         704 :   PetscFunctionBegin;
     127         704 :   PetscCall(MatShellGetContext(M,&matctx));
     128             : 
     129             : #if defined(PETSC_USE_COMPLEX)
     130         704 :   PetscCall(MatMult(matctx->B,x,matctx->w));
     131         704 :   PetscCall(MatSolve(matctx->F,matctx->w,y));
     132             : #else
     133             :   PetscCall(VecGetArrayRead(x,&X));
     134             :   PetscCall(VecGetArray(y,&Y));
     135             :   PetscCall(MatDenseGetArrayRead(matctx->S,&S));
     136             :   PetscCall(MatDenseGetLDA(matctx->S,&lds));
     137             : 
     138             :   n = matctx->n;
     139             :   PetscCall(PetscCalloc1(n*n,&C));
     140             :   PetscCall(PetscBLASIntCast(n,&n_));
     141             :   PetscCall(PetscBLASIntCast(lds,&lds_));
     142             : 
     143             :   /* C = 2*S*X*S.' */
     144             :   PetscCallBLAS("BLASgemm",BLASgemm_("N","N",&n_,&n_,&n_,&dtwo,S,&lds_,X,&n_,&zero,Y,&n_));
     145             :   PetscCallBLAS("BLASgemm",BLASgemm_("N","T",&n_,&n_,&n_,&done,Y,&n_,S,&lds_,&zero,C,&n_));
     146             : 
     147             :   /* Solve S*Y + Y*S' = -C */
     148             :   PetscCall(LMEDenseLyapunov(matctx->lme,n,(PetscScalar*)S,lds,C,n,Y,n));
     149             : 
     150             :   PetscCall(PetscFree(C));
     151             :   PetscCall(VecRestoreArrayRead(x,&X));
     152             :   PetscCall(VecRestoreArray(y,&Y));
     153             :   PetscCall(MatDenseRestoreArrayRead(matctx->S,&S));
     154             : #endif
     155         704 :   PetscFunctionReturn(PETSC_SUCCESS);
     156             : }
     157             : 
     158           3 : static PetscErrorCode MatDestroy_EigOperator(Mat M)
     159             : {
     160           3 :   EPS_EIG_MATSHELL *matctx;
     161             : 
     162           3 :   PetscFunctionBegin;
     163           3 :   PetscCall(MatShellGetContext(M,&matctx));
     164             : #if defined(PETSC_USE_COMPLEX)
     165           3 :   PetscCall(MatDestroy(&matctx->A));
     166           3 :   PetscCall(MatDestroy(&matctx->B));
     167           3 :   PetscCall(MatDestroy(&matctx->F));
     168           3 :   PetscCall(VecDestroy(&matctx->w));
     169             : #else
     170             :   PetscCall(MatDestroy(&matctx->S));
     171             : #endif
     172           3 :   PetscCall(PetscFree(matctx));
     173           3 :   PetscFunctionReturn(PETSC_SUCCESS);
     174             : }
     175             : 
     176             : /*
     177             :    EV2x2: solve the eigenproblem for a 2x2 matrix M
     178             :  */
     179          25 : static PetscErrorCode EV2x2(PetscScalar *M,PetscInt ld,PetscScalar *wr,PetscScalar *wi,PetscScalar *vec)
     180             : {
     181          25 :   PetscBLASInt   lwork=10,ld_;
     182          25 :   PetscScalar    work[10];
     183          25 :   PetscBLASInt   two=2,info;
     184             : #if defined(PETSC_USE_COMPLEX)
     185          25 :   PetscReal      rwork[6];
     186             : #endif
     187             : 
     188          25 :   PetscFunctionBegin;
     189          25 :   PetscCall(PetscBLASIntCast(ld,&ld_));
     190          25 :   PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
     191             : #if !defined(PETSC_USE_COMPLEX)
     192             :   PetscCallBLAS("LAPACKgeev",LAPACKgeev_("N","V",&two,M,&ld_,wr,wi,NULL,&ld_,vec,&ld_,work,&lwork,&info));
     193             : #else
     194          25 :   PetscCallBLAS("LAPACKgeev",LAPACKgeev_("N","V",&two,M,&ld_,wr,NULL,&ld_,vec,&ld_,work,&lwork,rwork,&info));
     195             : #endif
     196          25 :   SlepcCheckLapackInfo("geev",info);
     197          25 :   PetscCall(PetscFPTrapPop());
     198          25 :   PetscFunctionReturn(PETSC_SUCCESS);
     199             : }
     200             : 
     201             : /*
     202             :    LyapIIBuildRHS: prepare the right-hand side of the Lyapunov equation SY + YS' = -2*S*Z*S'
     203             :    in factored form:
     204             :       if (V)  U=sqrt(2)*S*V    (uses 1 work vector)
     205             :       else    U=sqrt(2)*S*U    (uses 2 work vectors)
     206             :    where U,V are assumed to have rk columns.
     207             :  */
     208          28 : static PetscErrorCode LyapIIBuildRHS(Mat S,PetscInt rk,Mat U,BV V,Vec *work)
     209             : {
     210          28 :   PetscScalar    *array,*uu;
     211          28 :   PetscInt       i,nloc;
     212          28 :   Vec            v,u=work[0];
     213             : 
     214          28 :   PetscFunctionBegin;
     215          28 :   PetscCall(MatGetLocalSize(U,&nloc,NULL));
     216          75 :   for (i=0;i<rk;i++) {
     217          47 :     PetscCall(MatDenseGetColumn(U,i,&array));
     218          47 :     if (V) PetscCall(BVGetColumn(V,i,&v));
     219             :     else {
     220          40 :       v = work[1];
     221          40 :       PetscCall(VecPlaceArray(v,array));
     222             :     }
     223          47 :     PetscCall(MatMult(S,v,u));
     224          47 :     if (V) PetscCall(BVRestoreColumn(V,i,&v));
     225          40 :     else PetscCall(VecResetArray(v));
     226          47 :     PetscCall(VecScale(u,PETSC_SQRT2));
     227          47 :     PetscCall(VecGetArray(u,&uu));
     228          47 :     PetscCall(PetscArraycpy(array,uu,nloc));
     229          47 :     PetscCall(VecRestoreArray(u,&uu));
     230          47 :     PetscCall(MatDenseRestoreColumn(U,&array));
     231             :   }
     232          28 :   PetscFunctionReturn(PETSC_SUCCESS);
     233             : }
     234             : 
     235             : /*
     236             :    LyapIIBuildEigenMat: create shell matrix Op=A\B with A = kron(I,S)+kron(S,I), B = -2*kron(S,S)
     237             :    where S is a sequential square dense matrix of order n.
     238             :    v0 is the initial vector, should have the form v0 = w*w' (for instance 1*1')
     239             :  */
     240          28 : static PetscErrorCode LyapIIBuildEigenMat(LME lme,Mat S,Mat *Op,Vec *v0)
     241             : {
     242          28 :   PetscInt          n,m;
     243          28 :   PetscBool         create=PETSC_FALSE;
     244          28 :   EPS_EIG_MATSHELL  *matctx;
     245             : #if defined(PETSC_USE_COMPLEX)
     246          28 :   PetscScalar       theta,*aa,*bb;
     247          28 :   const PetscScalar *ss;
     248          28 :   PetscInt          i,j,f,c,off,ld,lds;
     249          28 :   IS                perm;
     250             : #endif
     251             : 
     252          28 :   PetscFunctionBegin;
     253          28 :   PetscCall(MatGetSize(S,&n,NULL));
     254          28 :   if (!*Op) create=PETSC_TRUE;
     255             :   else {
     256          25 :     PetscCall(MatGetSize(*Op,&m,NULL));
     257          25 :     if (m!=n*n) create=PETSC_TRUE;
     258             :   }
     259          25 :   if (create) {
     260           3 :     PetscCall(MatDestroy(Op));
     261           3 :     PetscCall(VecDestroy(v0));
     262           3 :     PetscCall(PetscNew(&matctx));
     263             : #if defined(PETSC_USE_COMPLEX)
     264           3 :     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF,n*n,n*n,NULL,&matctx->A));
     265           3 :     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF,n*n,n*n,NULL,&matctx->B));
     266           3 :     PetscCall(MatCreateVecs(matctx->A,NULL,&matctx->w));
     267             : #else
     268             :     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF,n,n,NULL,&matctx->S));
     269             : #endif
     270           3 :     PetscCall(MatCreateShell(PETSC_COMM_SELF,n*n,n*n,PETSC_DETERMINE,PETSC_DETERMINE,matctx,Op));
     271           3 :     PetscCall(MatShellSetOperation(*Op,MATOP_MULT,(void(*)(void))MatMult_EigOperator));
     272           3 :     PetscCall(MatShellSetOperation(*Op,MATOP_DESTROY,(void(*)(void))MatDestroy_EigOperator));
     273           3 :     PetscCall(MatCreateVecs(*Op,NULL,v0));
     274             :   } else {
     275          25 :     PetscCall(MatShellGetContext(*Op,&matctx));
     276             : #if defined(PETSC_USE_COMPLEX)
     277          25 :     PetscCall(MatZeroEntries(matctx->A));
     278             : #endif
     279             :   }
     280             : #if defined(PETSC_USE_COMPLEX)
     281          28 :   PetscCall(MatDenseGetArray(matctx->A,&aa));
     282          28 :   PetscCall(MatDenseGetArray(matctx->B,&bb));
     283          28 :   PetscCall(MatDenseGetArrayRead(S,&ss));
     284          28 :   PetscCall(MatDenseGetLDA(S,&lds));
     285          28 :   ld = n*n;
     286         282 :   for (f=0;f<n;f++) {
     287         254 :     off = f*n+f*n*ld;
     288       24242 :     for (i=0;i<n;i++) for (j=0;j<n;j++) aa[off+i+j*ld] = ss[i+j*lds];
     289        2586 :     for (c=0;c<n;c++) {
     290        2332 :       off = f*n+c*n*ld;
     291        2332 :       theta = ss[f+c*lds];
     292       23988 :       for (i=0;i<n;i++) aa[off+i+i*ld] += theta;
     293      227236 :       for (i=0;i<n;i++) for (j=0;j<n;j++) bb[off+i+j*ld] = -2*theta*ss[i+j*lds];
     294             :     }
     295             :   }
     296          28 :   PetscCall(MatDenseRestoreArray(matctx->A,&aa));
     297          28 :   PetscCall(MatDenseRestoreArray(matctx->B,&bb));
     298          28 :   PetscCall(MatDenseRestoreArrayRead(S,&ss));
     299          28 :   PetscCall(ISCreateStride(PETSC_COMM_SELF,n*n,0,1,&perm));
     300          28 :   PetscCall(MatDestroy(&matctx->F));
     301          28 :   PetscCall(MatDuplicate(matctx->A,MAT_COPY_VALUES,&matctx->F));
     302          28 :   PetscCall(MatLUFactor(matctx->F,perm,perm,NULL));
     303          28 :   PetscCall(ISDestroy(&perm));
     304             : #else
     305             :   PetscCall(MatCopy(S,matctx->S,SAME_NONZERO_PATTERN));
     306             : #endif
     307          28 :   matctx->lme = lme;
     308          28 :   matctx->n = n;
     309          28 :   PetscCall(VecSet(*v0,1.0));
     310          28 :   PetscFunctionReturn(PETSC_SUCCESS);
     311             : }
     312             : 
     313           3 : static PetscErrorCode EPSSolve_LyapII(EPS eps)
     314             : {
     315           3 :   EPS_LYAPII          *ctx = (EPS_LYAPII*)eps->data;
     316           3 :   PetscInt            i,ldds,rk,nloc,mloc,nv,idx,k;
     317           3 :   Vec                 v,w,z=eps->work[0],v0=NULL;
     318           3 :   Mat                 S,C,Ux[2],Y,Y1,R,U,W,X,Op=NULL;
     319           3 :   BV                  V;
     320           3 :   BVOrthogType        type;
     321           3 :   BVOrthogRefineType  refine;
     322           3 :   PetscScalar         eigr[2],eigi[2],*array,er,ei,*uu,*s,*xx,*aa,pM[4],vec[4];
     323           3 :   PetscReal           eta;
     324           3 :   EPS                 epsrr;
     325           3 :   PetscReal           norm;
     326           3 :   EPS_LYAPII_MATSHELL *matctx;
     327             : 
     328           3 :   PetscFunctionBegin;
     329           3 :   PetscCall(DSGetLeadingDimension(ctx->ds,&ldds));
     330             : 
     331             :   /* Operator for the Lyapunov equation */
     332           3 :   PetscCall(PetscNew(&matctx));
     333           3 :   PetscCall(STGetOperator(eps->st,&matctx->S));
     334           3 :   PetscCall(MatGetLocalSize(matctx->S,&mloc,&nloc));
     335           3 :   PetscCall(MatCreateShell(PetscObjectComm((PetscObject)eps),mloc,nloc,PETSC_DETERMINE,PETSC_DETERMINE,matctx,&S));
     336           3 :   matctx->Q = eps->V;
     337           3 :   PetscCall(MatShellSetOperation(S,MATOP_MULT,(void(*)(void))MatMult_EPSLyapIIOperator));
     338           3 :   PetscCall(MatShellSetOperation(S,MATOP_DESTROY,(void(*)(void))MatDestroy_EPSLyapIIOperator));
     339           3 :   PetscCall(LMESetCoefficients(ctx->lme,S,NULL,NULL,NULL));
     340             : 
     341             :   /* Right-hand side */
     342           3 :   PetscCall(BVDuplicateResize(eps->V,ctx->rkl,&V));
     343           3 :   PetscCall(BVGetOrthogonalization(V,&type,&refine,&eta,NULL));
     344           3 :   PetscCall(BVSetOrthogonalization(V,type,refine,eta,BV_ORTHOG_BLOCK_TSQR));
     345           3 :   PetscCall(MatCreateDense(PetscObjectComm((PetscObject)eps),eps->nloc,PETSC_DECIDE,PETSC_DECIDE,1,NULL,&Ux[0]));
     346           3 :   PetscCall(MatCreateDense(PetscObjectComm((PetscObject)eps),eps->nloc,PETSC_DECIDE,PETSC_DECIDE,2,NULL,&Ux[1]));
     347           3 :   nv = ctx->rkl;
     348           3 :   PetscCall(PetscMalloc1(nv,&s));
     349             : 
     350             :   /* Initialize first column */
     351           3 :   PetscCall(EPSGetStartVector(eps,0,NULL));
     352           3 :   PetscCall(BVGetColumn(eps->V,0,&v));
     353           3 :   PetscCall(BVInsertVec(V,0,v));
     354           3 :   PetscCall(BVRestoreColumn(eps->V,0,&v));
     355           3 :   PetscCall(BVSetActiveColumns(eps->V,0,0));  /* no deflation at the beginning */
     356           3 :   PetscCall(LyapIIBuildRHS(S,1,Ux[0],V,eps->work));
     357           3 :   idx = 0;
     358             : 
     359             :   /* EPS for rank reduction */
     360           3 :   PetscCall(EPSCreate(PETSC_COMM_SELF,&epsrr));
     361           3 :   PetscCall(EPSSetOptionsPrefix(epsrr,((PetscObject)eps)->prefix));
     362           3 :   PetscCall(EPSAppendOptionsPrefix(epsrr,"eps_lyapii_"));
     363           3 :   PetscCall(EPSSetDimensions(epsrr,1,PETSC_CURRENT,PETSC_CURRENT));
     364           3 :   PetscCall(EPSSetTolerances(epsrr,PETSC_MACHINE_EPSILON*100,PETSC_CURRENT));
     365             : 
     366          31 :   while (eps->reason == EPS_CONVERGED_ITERATING) {
     367          28 :     eps->its++;
     368             : 
     369             :     /* Matrix for placing the solution of the Lyapunov equation (an alias of V) */
     370          28 :     PetscCall(BVSetActiveColumns(V,0,nv));
     371          28 :     PetscCall(BVGetMat(V,&Y1));
     372          28 :     PetscCall(MatZeroEntries(Y1));
     373          28 :     PetscCall(MatCreateLRC(NULL,Y1,NULL,NULL,&Y));
     374          28 :     PetscCall(LMESetSolution(ctx->lme,Y));
     375             : 
     376             :     /* Solve the Lyapunov equation SY + YS' = -2*S*Z*S' */
     377          28 :     PetscCall(MatCreateLRC(NULL,Ux[idx],NULL,NULL,&C));
     378          28 :     PetscCall(LMESetRHS(ctx->lme,C));
     379          28 :     PetscCall(MatDestroy(&C));
     380          28 :     PetscCall(LMESolve(ctx->lme));
     381          28 :     PetscCall(BVRestoreMat(V,&Y1));
     382          28 :     PetscCall(MatDestroy(&Y));
     383             : 
     384             :     /* SVD of the solution: [Q,R]=qr(V); [U,Sigma,~]=svd(R) */
     385          28 :     PetscCall(DSSetDimensions(ctx->ds,nv,0,0));
     386          28 :     PetscCall(DSSVDSetDimensions(ctx->ds,nv));
     387          28 :     PetscCall(DSGetMat(ctx->ds,DS_MAT_A,&R));
     388          28 :     PetscCall(BVOrthogonalize(V,R));
     389          28 :     PetscCall(DSRestoreMat(ctx->ds,DS_MAT_A,&R));
     390          28 :     PetscCall(DSSetState(ctx->ds,DS_STATE_RAW));
     391          28 :     PetscCall(DSSolve(ctx->ds,s,NULL));
     392             : 
     393             :     /* Determine rank */
     394         519 :     rk = nv;
     395         519 :     for (i=1;i<nv;i++) if (PetscAbsScalar(s[i]/s[0])<PETSC_SQRT_MACHINE_EPSILON) {rk=i; break;}
     396          28 :     PetscCall(PetscInfo(eps,"The computed solution of the Lyapunov equation has rank %" PetscInt_FMT "\n",rk));
     397          28 :     rk = PetscMin(rk,ctx->rkc);
     398          28 :     PetscCall(DSGetMat(ctx->ds,DS_MAT_U,&U));
     399          28 :     PetscCall(BVMultInPlace(V,U,0,rk));
     400          28 :     PetscCall(DSRestoreMat(ctx->ds,DS_MAT_U,&U));
     401          28 :     PetscCall(BVSetActiveColumns(V,0,rk));
     402             : 
     403             :     /* Rank reduction */
     404          28 :     PetscCall(DSSetDimensions(ctx->ds,rk,0,0));
     405          28 :     PetscCall(DSSVDSetDimensions(ctx->ds,rk));
     406          28 :     PetscCall(DSGetMat(ctx->ds,DS_MAT_A,&W));
     407          28 :     PetscCall(BVMatProject(V,S,V,W));
     408          28 :     PetscCall(LyapIIBuildEigenMat(ctx->lme,W,&Op,&v0)); /* Op=A\B, A=kron(I,S)+kron(S,I), B=-2*kron(S,S) */
     409          28 :     PetscCall(DSRestoreMat(ctx->ds,DS_MAT_A,&W));
     410          28 :     PetscCall(EPSSetOperators(epsrr,Op,NULL));
     411          28 :     PetscCall(EPSSetInitialSpace(epsrr,1,&v0));
     412          28 :     PetscCall(EPSSolve(epsrr));
     413          28 :     PetscCall(EPSComputeVectors(epsrr));
     414             :     /* Copy first eigenvector, vec(A)=x */
     415          28 :     PetscCall(BVGetArray(epsrr->V,&xx));
     416          28 :     PetscCall(DSGetArray(ctx->ds,DS_MAT_A,&aa));
     417         282 :     for (i=0;i<rk;i++) PetscCall(PetscArraycpy(aa+i*ldds,xx+i*rk,rk));
     418          28 :     PetscCall(DSRestoreArray(ctx->ds,DS_MAT_A,&aa));
     419          28 :     PetscCall(BVRestoreArray(epsrr->V,&xx));
     420          28 :     PetscCall(DSSetState(ctx->ds,DS_STATE_RAW));
     421             :     /* Compute [U,Sigma,~] = svd(A), its rank should be 1 or 2 */
     422          28 :     PetscCall(DSSolve(ctx->ds,s,NULL));
     423          28 :     if (PetscAbsScalar(s[1]/s[0])<PETSC_SQRT_MACHINE_EPSILON) rk=1;
     424          25 :     else rk = 2;
     425          28 :     PetscCall(PetscInfo(eps,"The eigenvector has rank %" PetscInt_FMT "\n",rk));
     426          28 :     PetscCall(DSGetMat(ctx->ds,DS_MAT_U,&U));
     427          28 :     PetscCall(BVMultInPlace(V,U,0,rk));
     428          28 :     PetscCall(DSRestoreMat(ctx->ds,DS_MAT_U,&U));
     429             : 
     430             :     /* Save V in Ux */
     431          28 :     idx = (rk==2)?1:0;
     432          81 :     for (i=0;i<rk;i++) {
     433          53 :       PetscCall(BVGetColumn(V,i,&v));
     434          53 :       PetscCall(VecGetArray(v,&uu));
     435          53 :       PetscCall(MatDenseGetColumn(Ux[idx],i,&array));
     436          53 :       PetscCall(PetscArraycpy(array,uu,eps->nloc));
     437          53 :       PetscCall(MatDenseRestoreColumn(Ux[idx],&array));
     438          53 :       PetscCall(VecRestoreArray(v,&uu));
     439          53 :       PetscCall(BVRestoreColumn(V,i,&v));
     440             :     }
     441             : 
     442             :     /* Eigenpair approximation */
     443          28 :     PetscCall(BVGetColumn(V,0,&v));
     444          28 :     PetscCall(MatMult(S,v,z));
     445          28 :     PetscCall(VecDot(z,v,pM));
     446          28 :     PetscCall(BVRestoreColumn(V,0,&v));
     447          28 :     if (rk>1) {
     448          25 :       PetscCall(BVGetColumn(V,1,&w));
     449          25 :       PetscCall(VecDot(z,w,pM+1));
     450          25 :       PetscCall(MatMult(S,w,z));
     451          25 :       PetscCall(VecDot(z,w,pM+3));
     452          25 :       PetscCall(BVGetColumn(V,0,&v));
     453          25 :       PetscCall(VecDot(z,v,pM+2));
     454          25 :       PetscCall(BVRestoreColumn(V,0,&v));
     455          25 :       PetscCall(BVRestoreColumn(V,1,&w));
     456          25 :       PetscCall(EV2x2(pM,2,eigr,eigi,vec));
     457          25 :       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF,2,2,vec,&X));
     458          25 :       PetscCall(BVSetActiveColumns(V,0,rk));
     459          25 :       PetscCall(BVMultInPlace(V,X,0,rk));
     460          25 :       PetscCall(MatDestroy(&X));
     461             : #if !defined(PETSC_USE_COMPLEX)
     462             :       norm = eigr[0]*eigr[0]+eigi[0]*eigi[0];
     463             :       er = eigr[0]/norm; ei = -eigi[0]/norm;
     464             : #else
     465          25 :       er =1.0/eigr[0]; ei = 0.0;
     466             : #endif
     467             :     } else {
     468           3 :       eigr[0] = pM[0]; eigi[0] = 0.0;
     469           3 :       er = 1.0/eigr[0]; ei = 0.0;
     470             :     }
     471          28 :     PetscCall(BVGetColumn(V,0,&v));
     472          28 :     if (eigi[0]!=0.0) PetscCall(BVGetColumn(V,1,&w));
     473          28 :     else w = NULL;
     474          28 :     eps->eigr[eps->nconv] = eigr[0]; eps->eigi[eps->nconv] = eigi[0];
     475          28 :     PetscCall(EPSComputeResidualNorm_Private(eps,PETSC_FALSE,er,ei,v,w,eps->work,&norm));
     476          28 :     PetscCall(BVRestoreColumn(V,0,&v));
     477          28 :     if (w) PetscCall(BVRestoreColumn(V,1,&w));
     478          28 :     PetscCall((*eps->converged)(eps,er,ei,norm,&eps->errest[eps->nconv],eps->convergedctx));
     479          28 :     k = 0;
     480          28 :     if (eps->errest[eps->nconv]<eps->tol) {
     481           7 :       k++;
     482           7 :       if (rk==2) {
     483             : #if !defined (PETSC_USE_COMPLEX)
     484             :         eps->eigr[eps->nconv+k] = eigr[0]; eps->eigi[eps->nconv+k] = -eigi[0];
     485             : #else
     486           6 :         eps->eigr[eps->nconv+k] = PetscConj(eps->eigr[eps->nconv]);
     487             : #endif
     488           6 :         k++;
     489             :       }
     490             :       /* Store converged eigenpairs and vectors for deflation */
     491          20 :       for (i=0;i<k;i++) {
     492          13 :         PetscCall(BVGetColumn(V,i,&v));
     493          13 :         PetscCall(BVInsertVec(eps->V,eps->nconv+i,v));
     494          13 :         PetscCall(BVRestoreColumn(V,i,&v));
     495             :       }
     496           7 :       eps->nconv += k;
     497           7 :       PetscCall(BVSetActiveColumns(eps->V,eps->nconv-rk,eps->nconv));
     498           7 :       PetscCall(BVOrthogonalize(eps->V,NULL));
     499           7 :       PetscCall(DSSetDimensions(eps->ds,eps->nconv,0,0));
     500           7 :       PetscCall(DSGetMat(eps->ds,DS_MAT_A,&W));
     501           7 :       PetscCall(BVMatProject(eps->V,matctx->S,eps->V,W));
     502           7 :       PetscCall(DSRestoreMat(eps->ds,DS_MAT_A,&W));
     503           7 :       if (eps->nconv<eps->nev) {
     504           4 :         idx = 0;
     505           4 :         PetscCall(BVSetRandomColumn(V,0));
     506           4 :         PetscCall(BVNormColumn(V,0,NORM_2,&norm));
     507           4 :         PetscCall(BVScaleColumn(V,0,1.0/norm));
     508           4 :         PetscCall(LyapIIBuildRHS(S,1,Ux[idx],V,eps->work));
     509             :       }
     510             :     } else {
     511             :       /* Prepare right-hand side */
     512          21 :       PetscCall(LyapIIBuildRHS(S,rk,Ux[idx],NULL,eps->work));
     513             :     }
     514          28 :     PetscCall((*eps->stopping)(eps,eps->its,eps->max_it,eps->nconv,eps->nev,&eps->reason,eps->stoppingctx));
     515          31 :     PetscCall(EPSMonitor(eps,eps->its,eps->nconv,eps->eigr,eps->eigi,eps->errest,eps->nconv+1));
     516             :   }
     517           3 :   PetscCall(STRestoreOperator(eps->st,&matctx->S));
     518           3 :   PetscCall(MatDestroy(&S));
     519           3 :   PetscCall(MatDestroy(&Ux[0]));
     520           3 :   PetscCall(MatDestroy(&Ux[1]));
     521           3 :   PetscCall(MatDestroy(&Op));
     522           3 :   PetscCall(VecDestroy(&v0));
     523           3 :   PetscCall(BVDestroy(&V));
     524           3 :   PetscCall(EPSDestroy(&epsrr));
     525           3 :   PetscCall(PetscFree(s));
     526           3 :   PetscFunctionReturn(PETSC_SUCCESS);
     527             : }
     528             : 
     529           3 : static PetscErrorCode EPSSetFromOptions_LyapII(EPS eps,PetscOptionItems *PetscOptionsObject)
     530             : {
     531           3 :   EPS_LYAPII     *ctx = (EPS_LYAPII*)eps->data;
     532           3 :   PetscInt       k,array[2]={PETSC_DETERMINE,PETSC_DETERMINE};
     533           3 :   PetscBool      flg;
     534             : 
     535           3 :   PetscFunctionBegin;
     536           3 :   PetscOptionsHeadBegin(PetscOptionsObject,"EPS Lyapunov Inverse Iteration Options");
     537             : 
     538           3 :     k = 2;
     539           3 :     PetscCall(PetscOptionsIntArray("-eps_lyapii_ranks","Ranks for Lyapunov equation (one or two comma-separated integers)","EPSLyapIISetRanks",array,&k,&flg));
     540           3 :     if (flg) PetscCall(EPSLyapIISetRanks(eps,array[0],array[1]));
     541             : 
     542           3 :   PetscOptionsHeadEnd();
     543             : 
     544           3 :   if (!ctx->lme) PetscCall(EPSLyapIIGetLME(eps,&ctx->lme));
     545           3 :   PetscCall(LMESetFromOptions(ctx->lme));
     546           3 :   PetscFunctionReturn(PETSC_SUCCESS);
     547             : }
     548             : 
     549           1 : static PetscErrorCode EPSLyapIISetRanks_LyapII(EPS eps,PetscInt rkc,PetscInt rkl)
     550             : {
     551           1 :   EPS_LYAPII *ctx = (EPS_LYAPII*)eps->data;
     552             : 
     553           1 :   PetscFunctionBegin;
     554           1 :   if (rkc==PETSC_DETERMINE) {
     555           0 :     if (ctx->rkc != 10) eps->state = EPS_STATE_INITIAL;
     556           0 :     ctx->rkc = 10;
     557           1 :   } else if (rkc!=PETSC_CURRENT) {
     558           1 :     PetscCheck(rkc>1,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The compressed rank %" PetscInt_FMT " must be larger than 1",rkc);
     559           1 :     if (ctx->rkc != rkc) eps->state = EPS_STATE_INITIAL;
     560           1 :     ctx->rkc = rkc;
     561             :   }
     562           1 :   if (rkl==PETSC_DETERMINE) {
     563           0 :     if (ctx->rkl != 3*rkc) eps->state = EPS_STATE_INITIAL;
     564           0 :     ctx->rkl = 3*rkc;
     565           1 :   } else if (rkl!=PETSC_CURRENT) {
     566           1 :     PetscCheck(rkl>=rkc,PetscObjectComm((PetscObject)eps),PETSC_ERR_ARG_OUTOFRANGE,"The Lyapunov rank %" PetscInt_FMT " cannot be smaller than the compressed rank %" PetscInt_FMT,rkl,rkc);
     567           1 :     if (ctx->rkl != rkl) eps->state = EPS_STATE_INITIAL;
     568           1 :     ctx->rkl = rkl;
     569             :   }
     570           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     571             : }
     572             : 
     573             : /*@
     574             :    EPSLyapIISetRanks - Set the ranks used in the solution of the Lyapunov equation.
     575             : 
     576             :    Logically Collective
     577             : 
     578             :    Input Parameters:
     579             : +  eps - the eigenproblem solver context
     580             : .  rkc - the compressed rank
     581             : -  rkl - the Lyapunov rank
     582             : 
     583             :    Options Database Key:
     584             : .  -eps_lyapii_ranks <rkc,rkl> - Sets the rank parameters
     585             : 
     586             :    Notes:
     587             :    PETSC_CURRENT can be used to preserve the current value of any of the
     588             :    arguments, and PETSC_DETERMINE to set them to a default value.
     589             : 
     590             :    Lyapunov inverse iteration needs to solve a large-scale Lyapunov equation
     591             :    at each iteration of the eigensolver. For this, an iterative solver (LME)
     592             :    is used, which requires to prescribe the rank of the solution matrix X. This
     593             :    is the meaning of parameter rkl. Later, this matrix is compressed into
     594             :    another matrix of rank rkc. If not provided, rkl is a small multiple of rkc.
     595             : 
     596             :    Level: intermediate
     597             : 
     598             : .seealso: EPSLyapIIGetRanks()
     599             : @*/
     600           1 : PetscErrorCode EPSLyapIISetRanks(EPS eps,PetscInt rkc,PetscInt rkl)
     601             : {
     602           1 :   PetscFunctionBegin;
     603           1 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
     604           3 :   PetscValidLogicalCollectiveInt(eps,rkc,2);
     605           3 :   PetscValidLogicalCollectiveInt(eps,rkl,3);
     606           1 :   PetscTryMethod(eps,"EPSLyapIISetRanks_C",(EPS,PetscInt,PetscInt),(eps,rkc,rkl));
     607           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     608             : }
     609             : 
     610           1 : static PetscErrorCode EPSLyapIIGetRanks_LyapII(EPS eps,PetscInt *rkc,PetscInt *rkl)
     611             : {
     612           1 :   EPS_LYAPII *ctx = (EPS_LYAPII*)eps->data;
     613             : 
     614           1 :   PetscFunctionBegin;
     615           1 :   if (rkc) *rkc = ctx->rkc;
     616           1 :   if (rkl) *rkl = ctx->rkl;
     617           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     618             : }
     619             : 
     620             : /*@
     621             :    EPSLyapIIGetRanks - Return the rank values used for the Lyapunov step.
     622             : 
     623             :    Not Collective
     624             : 
     625             :    Input Parameter:
     626             : .  eps - the eigenproblem solver context
     627             : 
     628             :    Output Parameters:
     629             : +  rkc - the compressed rank
     630             : -  rkl - the Lyapunov rank
     631             : 
     632             :    Level: intermediate
     633             : 
     634             : .seealso: EPSLyapIISetRanks()
     635             : @*/
     636           1 : PetscErrorCode EPSLyapIIGetRanks(EPS eps,PetscInt *rkc,PetscInt *rkl)
     637             : {
     638           1 :   PetscFunctionBegin;
     639           1 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
     640           1 :   PetscUseMethod(eps,"EPSLyapIIGetRanks_C",(EPS,PetscInt*,PetscInt*),(eps,rkc,rkl));
     641           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     642             : }
     643             : 
     644           0 : static PetscErrorCode EPSLyapIISetLME_LyapII(EPS eps,LME lme)
     645             : {
     646           0 :   EPS_LYAPII     *ctx = (EPS_LYAPII*)eps->data;
     647             : 
     648           0 :   PetscFunctionBegin;
     649           0 :   PetscCall(PetscObjectReference((PetscObject)lme));
     650           0 :   PetscCall(LMEDestroy(&ctx->lme));
     651           0 :   ctx->lme = lme;
     652           0 :   eps->state = EPS_STATE_INITIAL;
     653           0 :   PetscFunctionReturn(PETSC_SUCCESS);
     654             : }
     655             : 
     656             : /*@
     657             :    EPSLyapIISetLME - Associate a linear matrix equation solver object (LME) to the
     658             :    eigenvalue solver.
     659             : 
     660             :    Collective
     661             : 
     662             :    Input Parameters:
     663             : +  eps - the eigenproblem solver context
     664             : -  lme - the linear matrix equation solver object
     665             : 
     666             :    Level: advanced
     667             : 
     668             : .seealso: EPSLyapIIGetLME()
     669             : @*/
     670           0 : PetscErrorCode EPSLyapIISetLME(EPS eps,LME lme)
     671             : {
     672           0 :   PetscFunctionBegin;
     673           0 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
     674           0 :   PetscValidHeaderSpecific(lme,LME_CLASSID,2);
     675           0 :   PetscCheckSameComm(eps,1,lme,2);
     676           0 :   PetscTryMethod(eps,"EPSLyapIISetLME_C",(EPS,LME),(eps,lme));
     677           0 :   PetscFunctionReturn(PETSC_SUCCESS);
     678             : }
     679             : 
     680           3 : static PetscErrorCode EPSLyapIIGetLME_LyapII(EPS eps,LME *lme)
     681             : {
     682           3 :   EPS_LYAPII     *ctx = (EPS_LYAPII*)eps->data;
     683             : 
     684           3 :   PetscFunctionBegin;
     685           3 :   if (!ctx->lme) {
     686           3 :     PetscCall(LMECreate(PetscObjectComm((PetscObject)eps),&ctx->lme));
     687           3 :     PetscCall(LMESetOptionsPrefix(ctx->lme,((PetscObject)eps)->prefix));
     688           3 :     PetscCall(LMEAppendOptionsPrefix(ctx->lme,"eps_lyapii_"));
     689           3 :     PetscCall(PetscObjectIncrementTabLevel((PetscObject)ctx->lme,(PetscObject)eps,1));
     690             :   }
     691           3 :   *lme = ctx->lme;
     692           3 :   PetscFunctionReturn(PETSC_SUCCESS);
     693             : }
     694             : 
     695             : /*@
     696             :    EPSLyapIIGetLME - Retrieve the linear matrix equation solver object (LME)
     697             :    associated with the eigenvalue solver.
     698             : 
     699             :    Not Collective
     700             : 
     701             :    Input Parameter:
     702             : .  eps - the eigenproblem solver context
     703             : 
     704             :    Output Parameter:
     705             : .  lme - the linear matrix equation solver object
     706             : 
     707             :    Level: advanced
     708             : 
     709             : .seealso: EPSLyapIISetLME()
     710             : @*/
     711           3 : PetscErrorCode EPSLyapIIGetLME(EPS eps,LME *lme)
     712             : {
     713           3 :   PetscFunctionBegin;
     714           3 :   PetscValidHeaderSpecific(eps,EPS_CLASSID,1);
     715           3 :   PetscAssertPointer(lme,2);
     716           3 :   PetscUseMethod(eps,"EPSLyapIIGetLME_C",(EPS,LME*),(eps,lme));
     717           3 :   PetscFunctionReturn(PETSC_SUCCESS);
     718             : }
     719             : 
     720           1 : static PetscErrorCode EPSView_LyapII(EPS eps,PetscViewer viewer)
     721             : {
     722           1 :   EPS_LYAPII     *ctx = (EPS_LYAPII*)eps->data;
     723           1 :   PetscBool      isascii;
     724             : 
     725           1 :   PetscFunctionBegin;
     726           1 :   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
     727           1 :   if (isascii) {
     728           1 :     PetscCall(PetscViewerASCIIPrintf(viewer,"  ranks: for Lyapunov solver=%" PetscInt_FMT ", after compression=%" PetscInt_FMT "\n",ctx->rkl,ctx->rkc));
     729           1 :     if (!ctx->lme) PetscCall(EPSLyapIIGetLME(eps,&ctx->lme));
     730           1 :     PetscCall(PetscViewerASCIIPushTab(viewer));
     731           1 :     PetscCall(LMEView(ctx->lme,viewer));
     732           1 :     PetscCall(PetscViewerASCIIPopTab(viewer));
     733             :   }
     734           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     735             : }
     736             : 
     737           3 : static PetscErrorCode EPSReset_LyapII(EPS eps)
     738             : {
     739           3 :   EPS_LYAPII     *ctx = (EPS_LYAPII*)eps->data;
     740             : 
     741           3 :   PetscFunctionBegin;
     742           3 :   if (!ctx->lme) PetscCall(LMEReset(ctx->lme));
     743           3 :   PetscFunctionReturn(PETSC_SUCCESS);
     744             : }
     745             : 
     746           3 : static PetscErrorCode EPSDestroy_LyapII(EPS eps)
     747             : {
     748           3 :   EPS_LYAPII     *ctx = (EPS_LYAPII*)eps->data;
     749             : 
     750           3 :   PetscFunctionBegin;
     751           3 :   PetscCall(LMEDestroy(&ctx->lme));
     752           3 :   PetscCall(DSDestroy(&ctx->ds));
     753           3 :   PetscCall(PetscFree(eps->data));
     754           3 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSLyapIISetLME_C",NULL));
     755           3 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSLyapIIGetLME_C",NULL));
     756           3 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSLyapIISetRanks_C",NULL));
     757           3 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSLyapIIGetRanks_C",NULL));
     758           3 :   PetscFunctionReturn(PETSC_SUCCESS);
     759             : }
     760             : 
     761           6 : static PetscErrorCode EPSSetDefaultST_LyapII(EPS eps)
     762             : {
     763           6 :   PetscFunctionBegin;
     764           6 :   if (!((PetscObject)eps->st)->type_name) PetscCall(STSetType(eps->st,STSINVERT));
     765           6 :   PetscFunctionReturn(PETSC_SUCCESS);
     766             : }
     767             : 
     768           3 : SLEPC_EXTERN PetscErrorCode EPSCreate_LyapII(EPS eps)
     769             : {
     770           3 :   EPS_LYAPII     *ctx;
     771             : 
     772           3 :   PetscFunctionBegin;
     773           3 :   PetscCall(PetscNew(&ctx));
     774           3 :   eps->data = (void*)ctx;
     775             : 
     776           3 :   eps->useds = PETSC_TRUE;
     777             : 
     778           3 :   eps->ops->solve          = EPSSolve_LyapII;
     779           3 :   eps->ops->setup          = EPSSetUp_LyapII;
     780           3 :   eps->ops->setupsort      = EPSSetUpSort_Default;
     781           3 :   eps->ops->setfromoptions = EPSSetFromOptions_LyapII;
     782           3 :   eps->ops->reset          = EPSReset_LyapII;
     783           3 :   eps->ops->destroy        = EPSDestroy_LyapII;
     784           3 :   eps->ops->view           = EPSView_LyapII;
     785           3 :   eps->ops->setdefaultst   = EPSSetDefaultST_LyapII;
     786           3 :   eps->ops->backtransform  = EPSBackTransform_Default;
     787           3 :   eps->ops->computevectors = EPSComputeVectors_Schur;
     788             : 
     789           3 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSLyapIISetLME_C",EPSLyapIISetLME_LyapII));
     790           3 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSLyapIIGetLME_C",EPSLyapIIGetLME_LyapII));
     791           3 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSLyapIISetRanks_C",EPSLyapIISetRanks_LyapII));
     792           3 :   PetscCall(PetscObjectComposeFunction((PetscObject)eps,"EPSLyapIIGetRanks_C",EPSLyapIIGetRanks_LyapII));
     793           3 :   PetscFunctionReturn(PETSC_SUCCESS);
     794             : }

Generated by: LCOV version 1.14