LCOV - code coverage report
Current view: top level - eps/impls/krylov/krylovschur - ks-twosided.c (source / functions) Hit Total Coverage
Test: SLEPc Lines: 157 164 95.7 %
Date: 2024-04-19 00:31:36 Functions: 3 3 100.0 %
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: "krylovschur"
      12             : 
      13             :    Method: Two-sided Arnoldi with Krylov-Schur restart (for left eigenvectors)
      14             : 
      15             :    References:
      16             : 
      17             :        [1] I.N. Zwaan and M.E. Hochstenbach, "Krylov-Schur-type restarts
      18             :            for the two-sided Arnoldi method", SIAM J. Matrix Anal. Appl.
      19             :            38(2):297-321, 2017.
      20             : 
      21             : */
      22             : 
      23             : #include <slepc/private/epsimpl.h>
      24             : #include "krylovschur.h"
      25             : #include <slepcblaslapack.h>
      26             : 
      27          82 : static PetscErrorCode EPSTwoSidedRQUpdate1(EPS eps,Mat M,PetscInt nv,PetscReal beta,PetscReal betat)
      28             : {
      29          82 :   PetscScalar       *T,*S,*A,*w;
      30          82 :   const PetscScalar *pM;
      31          82 :   Vec               u;
      32          82 :   PetscInt          ld,ncv=eps->ncv,i,l,nnv;
      33          82 :   PetscBLASInt      info,n_,ncv_,*p,one=1;
      34             : 
      35          82 :   PetscFunctionBegin;
      36          82 :   PetscCall(DSGetLeadingDimension(eps->ds,&ld));
      37          82 :   PetscCall(PetscMalloc3(nv,&p,ncv*ncv,&A,ncv,&w));
      38          82 :   PetscCall(BVGetActiveColumns(eps->V,&l,&nnv));
      39          82 :   PetscCall(BVSetActiveColumns(eps->V,0,nv));
      40          82 :   PetscCall(BVSetActiveColumns(eps->W,0,nv));
      41          82 :   PetscCall(BVGetColumn(eps->V,nv,&u));
      42          82 :   PetscCall(BVDotVec(eps->W,u,w));
      43          82 :   PetscCall(BVRestoreColumn(eps->V,nv,&u));
      44          82 :   PetscCall(MatDenseGetArrayRead(M,&pM));
      45          82 :   PetscCall(PetscArraycpy(A,pM,ncv*ncv));
      46          82 :   PetscCall(MatDenseRestoreArrayRead(M,&pM));
      47          82 :   PetscCall(PetscBLASIntCast(nv,&n_));
      48          82 :   PetscCall(PetscBLASIntCast(ncv,&ncv_));
      49          82 :   PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
      50          82 :   PetscCallBLAS("LAPACKgetrf",LAPACKgetrf_(&n_,&n_,A,&ncv_,p,&info));
      51          82 :   SlepcCheckLapackInfo("getrf",info);
      52          82 :   PetscCall(PetscLogFlops(2.0*n_*n_*n_/3.0));
      53          82 :   PetscCallBLAS("LAPACKgetrs",LAPACKgetrs_("N",&n_,&one,A,&ncv_,p,w,&ncv_,&info));
      54          82 :   SlepcCheckLapackInfo("getrs",info);
      55          82 :   PetscCall(PetscLogFlops(2.0*n_*n_-n_));
      56          82 :   PetscCall(BVMultColumn(eps->V,-1.0,1.0,nv,w));
      57          82 :   PetscCall(DSGetArray(eps->ds,DS_MAT_A,&S));
      58        1650 :   for (i=0;i<nv;i++) S[(nv-1)*ld+i] += beta*w[i];
      59          82 :   PetscCall(DSRestoreArray(eps->ds,DS_MAT_A,&S));
      60          82 :   PetscCall(BVGetColumn(eps->W,nv,&u));
      61          82 :   PetscCall(BVDotVec(eps->V,u,w));
      62          82 :   PetscCall(BVRestoreColumn(eps->W,nv,&u));
      63          82 :   PetscCallBLAS("LAPACKgetrs",LAPACKgetrs_("C",&n_,&one,A,&ncv_,p,w,&ncv_,&info));
      64          82 :   PetscCall(PetscFPTrapPop());
      65          82 :   PetscCall(BVMultColumn(eps->W,-1.0,1.0,nv,w));
      66          82 :   PetscCall(DSGetArray(eps->ds,DS_MAT_B,&T));
      67        1650 :   for (i=0;i<nv;i++) T[(nv-1)*ld+i] += betat*w[i];
      68          82 :   PetscCall(DSRestoreArray(eps->ds,DS_MAT_B,&T));
      69          82 :   PetscCall(PetscFree3(p,A,w));
      70          82 :   PetscCall(BVSetActiveColumns(eps->V,l,nnv));
      71          82 :   PetscCall(BVSetActiveColumns(eps->W,l,nnv));
      72          82 :   PetscFunctionReturn(PETSC_SUCCESS);
      73             : }
      74             : 
      75          69 : static PetscErrorCode EPSTwoSidedRQUpdate2(EPS eps,Mat M,PetscInt k)
      76             : {
      77          69 :   PetscScalar    *Q,*pM,*w,zero=0.0,sone=1.0,*c,*A;
      78          69 :   PetscBLASInt   n_,ncv_,ld_;
      79          69 :   PetscReal      norm;
      80          69 :   PetscInt       l,nv,ncv=eps->ncv,ld,i,j;
      81             : 
      82          69 :   PetscFunctionBegin;
      83          69 :   PetscCall(DSGetLeadingDimension(eps->ds,&ld));
      84          69 :   PetscCall(BVGetActiveColumns(eps->V,&l,&nv));
      85          69 :   PetscCall(BVSetActiveColumns(eps->V,0,nv));
      86          69 :   PetscCall(BVSetActiveColumns(eps->W,0,nv));
      87          69 :   PetscCall(PetscMalloc2(ncv*ncv,&w,ncv,&c));
      88             :   /* u = u - V*V'*u */
      89          69 :   PetscCall(BVOrthogonalizeColumn(eps->V,k,c,&norm,NULL));
      90          69 :   PetscCall(BVScaleColumn(eps->V,k,1.0/norm));
      91          69 :   PetscCall(DSGetArray(eps->ds,DS_MAT_A,&A));
      92             :   /* H = H + V'*u*b' */
      93         714 :   for (j=l;j<k;j++) {
      94        6885 :     for (i=0;i<k;i++) A[i+j*ld] += c[i]*A[k+j*ld];
      95         645 :     A[k+j*ld] *= norm;
      96             :   }
      97          69 :   PetscCall(DSRestoreArray(eps->ds,DS_MAT_A,&A));
      98          69 :   PetscCall(BVOrthogonalizeColumn(eps->W,k,c,&norm,NULL));
      99          69 :   PetscCall(BVScaleColumn(eps->W,k,1.0/norm));
     100          69 :   PetscCall(DSGetArray(eps->ds,DS_MAT_B,&A));
     101             :   /* H = H + V'*u*b' */
     102         714 :   for (j=l;j<k;j++) {
     103        6885 :     for (i=0;i<k;i++) A[i+j*ld] += c[i]*A[k+j*ld];
     104         645 :     A[k+j*ld] *= norm;
     105             :   }
     106          69 :   PetscCall(DSRestoreArray(eps->ds,DS_MAT_B,&A));
     107             : 
     108             :   /* M = Q'*M*Q */
     109          69 :   PetscCall(MatDenseGetArray(M,&pM));
     110          69 :   PetscCall(PetscBLASIntCast(ncv,&ncv_));
     111          69 :   PetscCall(PetscBLASIntCast(nv,&n_));
     112          69 :   PetscCall(PetscBLASIntCast(ld,&ld_));
     113          69 :   PetscCall(DSGetArray(eps->ds,DS_MAT_Q,&Q));
     114          69 :   PetscCallBLAS("BLASgemm",BLASgemm_("N","N",&n_,&n_,&n_,&sone,pM,&ncv_,Q,&ld_,&zero,w,&ncv_));
     115          69 :   PetscCall(DSRestoreArray(eps->ds,DS_MAT_Q,&Q));
     116          69 :   PetscCall(DSGetArray(eps->ds,DS_MAT_Z,&Q));
     117          69 :   PetscCallBLAS("BLASgemm",BLASgemm_("C","N",&n_,&n_,&n_,&sone,Q,&ld_,w,&ncv_,&zero,pM,&ncv_));
     118          69 :   PetscCall(DSRestoreArray(eps->ds,DS_MAT_Z,&Q));
     119          69 :   PetscCall(MatDenseRestoreArray(M,&pM));
     120          69 :   PetscCall(PetscFree2(w,c));
     121          69 :   PetscCall(BVSetActiveColumns(eps->V,l,nv));
     122          69 :   PetscCall(BVSetActiveColumns(eps->W,l,nv));
     123          69 :   PetscFunctionReturn(PETSC_SUCCESS);
     124             : }
     125             : 
     126          13 : PetscErrorCode EPSSolve_KrylovSchur_TwoSided(EPS eps)
     127             : {
     128          13 :   EPS_KRYLOVSCHUR *ctx = (EPS_KRYLOVSCHUR*)eps->data;
     129          13 :   Mat             M,U,Op,OpHT,S,T;
     130          13 :   PetscReal       norm,norm2,beta,betat;
     131          13 :   PetscInt        ld,l,nv,nvt,k,nconv,dsn,dsk;
     132          13 :   PetscBool       breakdownt,breakdown,breakdownl;
     133             : 
     134          13 :   PetscFunctionBegin;
     135          13 :   PetscCall(DSGetLeadingDimension(eps->ds,&ld));
     136          13 :   PetscCall(EPSGetStartVector(eps,0,NULL));
     137          13 :   PetscCall(EPSGetLeftStartVector(eps,0,NULL));
     138          13 :   l = 0;
     139          13 :   PetscCall(MatCreateSeqDense(PETSC_COMM_SELF,eps->ncv,eps->ncv,NULL,&M));
     140             : 
     141          13 :   PetscCall(STGetOperator(eps->st,&Op));
     142          13 :   PetscCall(MatCreateHermitianTranspose(Op,&OpHT));
     143             : 
     144             :   /* Restart loop */
     145          95 :   while (eps->reason == EPS_CONVERGED_ITERATING) {
     146          82 :     eps->its++;
     147             : 
     148             :     /* Compute an nv-step Arnoldi factorization for Op */
     149          82 :     nv = PetscMin(eps->nconv+eps->mpd,eps->ncv);
     150          82 :     PetscCall(DSSetDimensions(eps->ds,nv,eps->nconv,eps->nconv+l));
     151          82 :     PetscCall(DSGetMat(eps->ds,DS_MAT_A,&S));
     152          82 :     PetscCall(BVMatArnoldi(eps->V,Op,S,eps->nconv+l,&nv,&beta,&breakdown));
     153          82 :     PetscCall(DSRestoreMat(eps->ds,DS_MAT_A,&S));
     154             : 
     155             :     /* Compute an nv-step Arnoldi factorization for Op' */
     156          82 :     nvt = nv;
     157          82 :     PetscCall(DSSetDimensions(eps->ds,nv,eps->nconv,eps->nconv+l));
     158          82 :     PetscCall(DSGetMat(eps->ds,DS_MAT_B,&T));
     159          82 :     PetscCall(BVMatArnoldi(eps->W,OpHT,T,eps->nconv+l,&nvt,&betat,&breakdownt));
     160          82 :     PetscCall(DSRestoreMat(eps->ds,DS_MAT_B,&T));
     161             : 
     162             :     /* Make sure both factorizations have the same length */
     163          82 :     nv = PetscMin(nv,nvt);
     164          82 :     PetscCall(DSSetDimensions(eps->ds,nv,eps->nconv,eps->nconv+l));
     165          82 :     if (l==0) PetscCall(DSSetState(eps->ds,DS_STATE_INTERMEDIATE));
     166          69 :     else PetscCall(DSSetState(eps->ds,DS_STATE_RAW));
     167          82 :     breakdown = (breakdown || breakdownt)? PETSC_TRUE: PETSC_FALSE;
     168             : 
     169             :     /* Update M, modify Rayleigh quotients S and T */
     170          82 :     PetscCall(BVSetActiveColumns(eps->V,eps->nconv+l,nv));
     171          82 :     PetscCall(BVSetActiveColumns(eps->W,eps->nconv+l,nv));
     172          82 :     PetscCall(BVMatProject(eps->V,NULL,eps->W,M));
     173             : 
     174          82 :     PetscCall(EPSTwoSidedRQUpdate1(eps,M,nv,beta,betat));
     175             : 
     176             :     /* Solve projected problem */
     177          82 :     PetscCall(DSSolve(eps->ds,eps->eigr,eps->eigi));
     178          82 :     PetscCall(DSSort(eps->ds,eps->eigr,eps->eigi,NULL,NULL,NULL));
     179          82 :     PetscCall(DSSynchronize(eps->ds,eps->eigr,eps->eigi));
     180          82 :     PetscCall(DSUpdateExtraRow(eps->ds));
     181             : 
     182             :     /* Check convergence */
     183          82 :     PetscCall(BVNormColumn(eps->V,nv,NORM_2,&norm));
     184          82 :     PetscCall(BVNormColumn(eps->W,nv,NORM_2,&norm2));
     185          82 :     PetscCall(EPSKrylovConvergence(eps,PETSC_FALSE,eps->nconv,nv-eps->nconv,beta*norm,betat*norm2,1.0,&k));
     186          82 :     PetscCall((*eps->stopping)(eps,eps->its,eps->max_it,k,eps->nev,&eps->reason,eps->stoppingctx));
     187          82 :     nconv = k;
     188             : 
     189             :     /* Update l */
     190          82 :     if (eps->reason != EPS_CONVERGED_ITERATING || breakdown || k==nv) l = 0;
     191             :     else {
     192          69 :       l = PetscMax(1,(PetscInt)((nv-k)*ctx->keep));
     193          69 :       PetscCall(DSGetTruncateSize(eps->ds,k,nv,&l));
     194             :     }
     195          82 :     if (!ctx->lock && l>0) { l += k; k = 0; } /* non-locking variant: reset no. of converged pairs */
     196          82 :     if (l) PetscCall(PetscInfo(eps,"Preparing to restart keeping l=%" PetscInt_FMT " vectors\n",l));
     197             : 
     198             :     /* Update the corresponding vectors V(:,idx) = V*Q(:,idx) */
     199          82 :     PetscCall(BVSetActiveColumns(eps->V,eps->nconv,nv));
     200          82 :     PetscCall(BVSetActiveColumns(eps->W,eps->nconv,nv));
     201          82 :     PetscCall(DSGetMat(eps->ds,DS_MAT_Q,&U));
     202          82 :     PetscCall(BVMultInPlace(eps->V,U,eps->nconv,k+l));
     203          82 :     PetscCall(DSRestoreMat(eps->ds,DS_MAT_Q,&U));
     204          82 :     PetscCall(DSGetMat(eps->ds,DS_MAT_Z,&U));
     205          82 :     PetscCall(BVMultInPlace(eps->W,U,eps->nconv,k+l));
     206          82 :     PetscCall(DSRestoreMat(eps->ds,DS_MAT_Z,&U));
     207          82 :     if (eps->reason == EPS_CONVERGED_ITERATING && !breakdown) {
     208          69 :       PetscCall(BVCopyColumn(eps->V,nv,k+l));
     209          69 :       PetscCall(BVCopyColumn(eps->W,nv,k+l));
     210             :     }
     211             : 
     212          82 :     if (eps->reason == EPS_CONVERGED_ITERATING) {
     213          69 :       if (breakdown || k==nv) {
     214             :         /* Start a new Arnoldi factorization */
     215           0 :         PetscCall(PetscInfo(eps,"Breakdown in Krylov-Schur method (it=%" PetscInt_FMT " norm=%g)\n",eps->its,(double)beta));
     216           0 :         if (k<eps->nev) {
     217           0 :           PetscCall(EPSGetStartVector(eps,k,&breakdown));
     218           0 :           PetscCall(EPSGetLeftStartVector(eps,k,&breakdownl));
     219           0 :           if (breakdown || breakdownl) {
     220           0 :             eps->reason = EPS_DIVERGED_BREAKDOWN;
     221           0 :             PetscCall(PetscInfo(eps,"Unable to generate more start vectors\n"));
     222             :           }
     223             :         }
     224             :       } else {
     225          69 :         PetscCall(DSGetDimensions(eps->ds,&dsn,NULL,&dsk,NULL));
     226          69 :         PetscCall(DSSetDimensions(eps->ds,dsn,k,dsk));
     227          69 :         PetscCall(DSTruncate(eps->ds,k+l,PETSC_FALSE));
     228             :       }
     229          69 :       PetscCall(EPSTwoSidedRQUpdate2(eps,M,k+l));
     230             :     }
     231          82 :     eps->nconv = k;
     232          95 :     PetscCall(EPSMonitor(eps,eps->its,nconv,eps->eigr,eps->eigi,eps->errest,nv));
     233             :   }
     234             : 
     235          13 :   PetscCall(STRestoreOperator(eps->st,&Op));
     236          13 :   PetscCall(MatDestroy(&OpHT));
     237             : 
     238          13 :   PetscCall(DSTruncate(eps->ds,eps->nconv,PETSC_TRUE));
     239          13 :   PetscCall(MatDestroy(&M));
     240          13 :   PetscFunctionReturn(PETSC_SUCCESS);
     241             : }

Generated by: LCOV version 1.14