LCOV - code coverage report
Current view: top level - lme/impls/krylov - lmekrylov.c (source / functions) Hit Total Coverage
Test: SLEPc Lines: 121 123 98.4 %
Date: 2024-11-21 00:34:55 Functions: 4 4 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 matrix equation solver: "krylov"
      12             : 
      13             :    Method: Arnoldi with Eiermann-Ernst restart
      14             : 
      15             :    Algorithm:
      16             : 
      17             :        Project the equation onto the Arnoldi basis and solve the compressed
      18             :        equation the Hessenberg matrix H, restart by discarding the Krylov
      19             :        basis but keeping H.
      20             : 
      21             :    References:
      22             : 
      23             :        [1] Y. Saad, "Numerical solution of large Lyapunov equations", in
      24             :            Signal processing, scattering and operator theory, and numerical
      25             :            methods, vol. 5 of Progr. Systems Control Theory, pages 503-511,
      26             :            1990.
      27             : 
      28             :        [2] D. Kressner, "Memory-efficient Krylov subspace techniques for
      29             :            solving large-scale Lyapunov equations", in 2008 IEEE Int. Conf.
      30             :            Computer-Aided Control Systems, pages 613-618, 2008.
      31             : */
      32             : 
      33             : #include <slepc/private/lmeimpl.h>
      34             : #include <slepcblaslapack.h>
      35             : 
      36           7 : static PetscErrorCode LMESetUp_Krylov(LME lme)
      37             : {
      38           7 :   PetscInt       N;
      39             : 
      40           7 :   PetscFunctionBegin;
      41           7 :   PetscCall(MatGetSize(lme->A,&N,NULL));
      42           7 :   if (lme->ncv==PETSC_DETERMINE) lme->ncv = PetscMin(30,N);
      43           7 :   if (lme->max_it==PETSC_DETERMINE) lme->max_it = 100;
      44           7 :   PetscCall(LMEAllocateSolution(lme,1));
      45           7 :   PetscFunctionReturn(PETSC_SUCCESS);
      46             : }
      47             : 
      48          51 : static PetscErrorCode LMESolve_Krylov_Lyapunov_Vec(LME lme,Vec b,PetscBool fixed,PetscInt rrank,BV C1,BV *X1,PetscInt *col,PetscBool *fail,PetscInt *totalits)
      49             : {
      50          51 :   PetscInt       n=0,m,ldh,ldg=0,i,j,rank=0,lrank,pass,nouter=0,its;
      51          51 :   PetscReal      bnorm,beta,errest;
      52          51 :   PetscBool      breakdown;
      53          51 :   PetscScalar    *Harray,*G=NULL,*Gnew=NULL,*L=NULL,*U=NULL,*r,*Qarray,sone=1.0,zero=0.0;
      54          51 :   PetscBLASInt   n_,m_,rk_;
      55          51 :   Mat            Q,H;
      56             : 
      57          51 :   PetscFunctionBegin;
      58          51 :   *fail = PETSC_FALSE;
      59          51 :   its = 0;
      60          51 :   m  = lme->ncv;
      61          51 :   ldh = m+1;
      62          51 :   PetscCall(MatCreateSeqDense(PETSC_COMM_SELF,ldh,m,NULL,&H));
      63          51 :   PetscCall(MatDenseGetArray(H,&Harray));
      64             : 
      65          51 :   PetscCall(VecNorm(b,NORM_2,&bnorm));
      66          51 :   PetscCheck(bnorm,PetscObjectComm((PetscObject)lme),PETSC_ERR_ARG_WRONG,"Cannot process a zero vector in the right-hand side");
      67             : 
      68         153 :   for (pass=0;pass<2;pass++) {
      69             : 
      70             :     /* set initial vector to b/||b|| */
      71         102 :     PetscCall(BVInsertVec(lme->V,0,b));
      72         102 :     PetscCall(BVScaleColumn(lme->V,0,1.0/bnorm));
      73             : 
      74             :     /* Restart loop */
      75         161 :     while ((pass==0 && !*fail) || (pass==1 && its+1<nouter)) {
      76         110 :       its++;
      77             : 
      78             :       /* compute Arnoldi factorization */
      79         110 :       PetscCall(BVMatArnoldi(lme->V,lme->A,H,0,&m,&beta,&breakdown));
      80         110 :       PetscCall(BVSetActiveColumns(lme->V,0,m));
      81             : 
      82         110 :       if (pass==0) {
      83             :         /* glue together the previous H and the new H obtained with Arnoldi */
      84          55 :         ldg = n+m+1;
      85          55 :         PetscCall(PetscCalloc1(ldg*(n+m),&Gnew));
      86        1633 :         for (j=0;j<m;j++) PetscCall(PetscArraycpy(Gnew+n+(j+n)*ldg,Harray+j*ldh,m));
      87          55 :         Gnew[n+m+(n+m-1)*ldg] = beta;
      88          55 :         if (G) {
      89          88 :           for (j=0;j<n;j++) PetscCall(PetscArraycpy(Gnew+j*ldg,G+j*(n+1),n+1));
      90           4 :           PetscCall(PetscFree(G));
      91             :         }
      92          55 :         G = Gnew;
      93          55 :         n += m;
      94             :       } else {
      95             :         /* update Z = Z + V(:,1:m)*Q    with   Q=U(blk,:)*P(1:nrk,:)'  */
      96          55 :         PetscCall(MatCreateSeqDense(PETSC_COMM_SELF,m,*col+rank,NULL,&Q));
      97          55 :         PetscCall(MatDenseGetArray(Q,&Qarray));
      98          55 :         PetscCall(PetscBLASIntCast(m,&m_));
      99          55 :         PetscCall(PetscBLASIntCast(n,&n_));
     100          55 :         PetscCall(PetscBLASIntCast(rank,&rk_));
     101          55 :         PetscCallBLAS("BLASgemm",BLASgemm_("N","N",&m_,&rk_,&rk_,&sone,U+its*m,&n_,L,&n_,&zero,Qarray+(*col)*m,&m_));
     102          55 :         PetscCall(MatDenseRestoreArray(Q,&Qarray));
     103          55 :         PetscCall(BVSetActiveColumns(*X1,*col,*col+rank));
     104          55 :         PetscCall(BVMult(*X1,1.0,1.0,lme->V,Q));
     105          55 :         PetscCall(MatDestroy(&Q));
     106             :       }
     107             : 
     108         110 :       if (pass==0) {
     109             :         /* solve compressed Lyapunov equation */
     110          55 :         PetscCall(PetscCalloc1(n,&r));
     111          55 :         PetscCall(PetscCalloc1(n*n,&L));
     112          55 :         r[0] = bnorm;
     113          55 :         errest = PetscAbsScalar(G[n+(n-1)*ldg]);
     114          55 :         PetscCall(LMEDenseHessLyapunovChol(lme,n,G,ldg,1,r,n,L,n,&errest));
     115          55 :         PetscCall(LMEMonitor(lme,*totalits+its,errest));
     116          55 :         PetscCall(PetscFree(r));
     117             : 
     118             :         /* check convergence */
     119          55 :         if (errest<lme->tol) {
     120          51 :           lme->errest += errest;
     121          51 :           PetscCall(PetscMalloc1(n*n,&U));
     122             :           /* transpose L */
     123        1629 :           for (j=0;j<n;j++) {
     124       25467 :             for (i=j+1;i<n;i++) {
     125       23889 :               L[i+j*n] = PetscConj(L[j+i*n]);
     126       23889 :               L[j+i*n] = 0.0;
     127             :             }
     128             :           }
     129          51 :           PetscCall(LMEDenseRankSVD(lme,n,L,n,U,n,&lrank));
     130          51 :           PetscCall(PetscInfo(lme,"Rank of the Cholesky factor = %" PetscInt_FMT "\n",lrank));
     131          51 :           nouter = its;
     132          51 :           its = -1;
     133          51 :           if (!fixed) {  /* X1 was not set by user, allocate it with rank columns */
     134           6 :             rank = lrank;
     135           6 :             if (*col) PetscCall(BVResize(*X1,*col+rank,PETSC_TRUE));
     136           3 :             else PetscCall(BVDuplicateResize(C1,rank,X1));
     137          45 :           } else rank = PetscMin(lrank,rrank);
     138          51 :           PetscCall(PetscFree(G));
     139             :           break;
     140             :         } else {
     141           4 :           PetscCall(PetscFree(L));
     142           4 :           if (*totalits+its>=lme->max_it) *fail = PETSC_TRUE;
     143             :         }
     144             :       }
     145             : 
     146             :       /* restart with vector v_{m+1} */
     147         220 :       if (!*fail) PetscCall(BVCopyColumn(lme->V,m,0));
     148             :     }
     149             :   }
     150             : 
     151          51 :   *col += rank;
     152          51 :   *totalits += its+1;
     153          51 :   PetscCall(MatDenseRestoreArray(H,&Harray));
     154          51 :   PetscCall(MatDestroy(&H));
     155          51 :   if (L) PetscCall(PetscFree(L));
     156          51 :   if (U) PetscCall(PetscFree(U));
     157          51 :   PetscFunctionReturn(PETSC_SUCCESS);
     158             : }
     159             : 
     160          30 : static PetscErrorCode LMESolve_Krylov_Lyapunov(LME lme)
     161             : {
     162          30 :   PetscBool      fail,fixed = lme->X? PETSC_TRUE: PETSC_FALSE;
     163          30 :   PetscInt       i,k,rank=0,col=0;
     164          30 :   Vec            b;
     165          30 :   BV             X1=NULL,C1;
     166          30 :   Mat            X1m,X1t,C1m;
     167             : 
     168          30 :   PetscFunctionBegin;
     169          30 :   PetscCall(MatLRCGetMats(lme->C,NULL,&C1m,NULL,NULL));
     170          30 :   PetscCall(BVCreateFromMat(C1m,&C1));
     171          30 :   PetscCall(BVSetFromOptions(C1));
     172          30 :   PetscCall(BVGetActiveColumns(C1,NULL,&k));
     173          30 :   if (fixed) {
     174          27 :     PetscCall(MatLRCGetMats(lme->X,NULL,&X1m,NULL,NULL));
     175          27 :     PetscCall(BVCreateFromMat(X1m,&X1));
     176          27 :     PetscCall(BVSetFromOptions(X1));
     177          27 :     PetscCall(BVGetActiveColumns(X1,NULL,&rank));
     178          27 :     rank = rank/k;
     179             :   }
     180          81 :   for (i=0;i<k;i++) {
     181          51 :     PetscCall(BVGetColumn(C1,i,&b));
     182          51 :     PetscCall(LMESolve_Krylov_Lyapunov_Vec(lme,b,fixed,rank,C1,&X1,&col,&fail,&lme->its));
     183          51 :     PetscCall(BVRestoreColumn(C1,i,&b));
     184          51 :     if (fail) {
     185           0 :       lme->reason = LME_DIVERGED_ITS;
     186           0 :       break;
     187             :     }
     188             :   }
     189          30 :   if (lme->reason==LME_CONVERGED_ITERATING) lme->reason = LME_CONVERGED_TOL;
     190          30 :   PetscCall(BVCreateMat(X1,&X1t));
     191          30 :   if (fixed) PetscCall(MatCopy(X1t,X1m,SAME_NONZERO_PATTERN));
     192           3 :   else PetscCall(MatCreateLRC(NULL,X1t,NULL,NULL,&lme->X));
     193          30 :   PetscCall(MatDestroy(&X1t));
     194          30 :   PetscCall(BVDestroy(&C1));
     195          30 :   PetscCall(BVDestroy(&X1));
     196          30 :   PetscFunctionReturn(PETSC_SUCCESS);
     197             : }
     198             : 
     199           7 : SLEPC_EXTERN PetscErrorCode LMECreate_Krylov(LME lme)
     200             : {
     201           7 :   PetscFunctionBegin;
     202           7 :   lme->ops->solve[LME_LYAPUNOV]      = LMESolve_Krylov_Lyapunov;
     203           7 :   lme->ops->setup                    = LMESetUp_Krylov;
     204           7 :   PetscFunctionReturn(PETSC_SUCCESS);
     205             : }

Generated by: LCOV version 1.14