LCOV - code coverage report
Current view: top level - lme/interface - lmedense.c (source / functions) Hit Total Coverage
Test: SLEPc Lines: 175 175 100.0 %
Date: 2024-12-18 00:51:33 Functions: 8 8 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             :    Routines for solving dense matrix equations, in some cases calling SLICOT
      12             : */
      13             : 
      14             : #include <slepc/private/lmeimpl.h>     /*I "slepclme.h" I*/
      15             : #include <slepcblaslapack.h>
      16             : 
      17             : /*
      18             :    LMEDenseRankSVD - given a square matrix A, compute its SVD U*S*V', and determine the
      19             :    numerical rank. On exit, U contains U*S and A is overwritten with V'
      20             : */
      21          55 : PetscErrorCode LMEDenseRankSVD(LME lme,PetscInt n,PetscScalar *A,PetscInt lda,PetscScalar *U,PetscInt ldu,PetscInt *rank)
      22             : {
      23          55 :   PetscInt       i,j,rk=0;
      24          55 :   PetscScalar    *work;
      25          55 :   PetscReal      tol,*sg,*rwork;
      26          55 :   PetscBLASInt   n_,lda_,ldu_,info,lw_;
      27             : 
      28          55 :   PetscFunctionBegin;
      29          55 :   PetscCall(PetscCalloc3(n,&sg,10*n,&work,5*n,&rwork));
      30          55 :   PetscCall(PetscBLASIntCast(n,&n_));
      31          55 :   PetscCall(PetscBLASIntCast(lda,&lda_));
      32          55 :   PetscCall(PetscBLASIntCast(ldu,&ldu_));
      33          55 :   lw_ = 10*n_;
      34          55 :   PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
      35             : #if !defined (PETSC_USE_COMPLEX)
      36             :   PetscCallBLAS("LAPACKgesvd",LAPACKgesvd_("S","O",&n_,&n_,A,&lda_,sg,U,&ldu_,NULL,&n_,work,&lw_,&info));
      37             : #else
      38          55 :   PetscCallBLAS("LAPACKgesvd",LAPACKgesvd_("S","O",&n_,&n_,A,&lda_,sg,U,&ldu_,NULL,&n_,work,&lw_,rwork,&info));
      39             : #endif
      40          55 :   PetscCall(PetscFPTrapPop());
      41          55 :   SlepcCheckLapackInfo("gesvd",info);
      42          55 :   tol = 10*PETSC_MACHINE_EPSILON*n*sg[0];
      43        1753 :   for (j=0;j<n;j++) {
      44        1698 :     if (sg[j]>tol) {
      45       54654 :       for (i=0;i<n;i++) U[i+j*n] *= sg[j];
      46        1698 :       rk++;
      47             :     } else break;
      48             :   }
      49          55 :   *rank = rk;
      50          55 :   PetscCall(PetscFree3(sg,work,rwork));
      51          55 :   PetscFunctionReturn(PETSC_SUCCESS);
      52             : }
      53             : 
      54             : #if defined(PETSC_USE_INFO)
      55             : /*
      56             :    LyapunovCholResidual - compute the residual norm ||A*U'*U+U'*U*A'+B*B'||
      57             : */
      58           1 : static PetscErrorCode LyapunovCholResidual(PetscInt m,PetscScalar *A,PetscInt lda,PetscInt k,PetscScalar *B,PetscInt ldb,PetscScalar *U,PetscInt ldu,PetscReal *res)
      59             : {
      60           1 :   PetscBLASInt   n,kk,la,lb,lu;
      61           1 :   PetscScalar    *M,*R,zero=0.0,done=1.0;
      62             : 
      63           1 :   PetscFunctionBegin;
      64           1 :   *res = 0;
      65           1 :   PetscCall(PetscBLASIntCast(lda,&la));
      66           1 :   PetscCall(PetscBLASIntCast(ldb,&lb));
      67           1 :   PetscCall(PetscBLASIntCast(ldu,&lu));
      68           1 :   PetscCall(PetscBLASIntCast(m,&n));
      69           1 :   PetscCall(PetscBLASIntCast(k,&kk));
      70           1 :   PetscCall(PetscMalloc2(m*m,&M,m*m,&R));
      71             : 
      72             :   /* R = B*B' */
      73           1 :   PetscCallBLAS("BLASgemm",BLASgemm_("N","C",&n,&n,&kk,&done,B,&lb,B,&lb,&zero,R,&n));
      74             :   /* M = A*U' */
      75           1 :   PetscCallBLAS("BLASgemm",BLASgemm_("N","C",&n,&n,&n,&done,A,&la,U,&lu,&zero,M,&n));
      76             :   /* R = R+M*U */
      77           1 :   PetscCallBLAS("BLASgemm",BLASgemm_("N","N",&n,&n,&n,&done,M,&n,U,&lu,&done,R,&n));
      78             :   /* R = R+U'*M' */
      79           1 :   PetscCallBLAS("BLASgemm",BLASgemm_("C","C",&n,&n,&n,&done,U,&lu,M,&n,&done,R,&n));
      80             : 
      81           1 :   *res = LAPACKlange_("F",&n,&n,R,&n,NULL);
      82           1 :   PetscCall(PetscFree2(M,R));
      83           1 :   PetscFunctionReturn(PETSC_SUCCESS);
      84             : }
      85             : 
      86             : /*
      87             :    LyapunovResidual - compute the residual norm ||A*X+X*A'+B||
      88             : */
      89           1 : static PetscErrorCode LyapunovResidual(PetscInt m,PetscScalar *A,PetscInt lda,PetscScalar *B,PetscInt ldb,PetscScalar *X,PetscInt ldx,PetscReal *res)
      90             : {
      91           1 :   PetscInt       i;
      92           1 :   PetscBLASInt   n,la,lb,lx;
      93           1 :   PetscScalar    *R,done=1.0;
      94             : 
      95           1 :   PetscFunctionBegin;
      96           1 :   *res = 0;
      97           1 :   PetscCall(PetscBLASIntCast(lda,&la));
      98           1 :   PetscCall(PetscBLASIntCast(ldb,&lb));
      99           1 :   PetscCall(PetscBLASIntCast(ldx,&lx));
     100           1 :   PetscCall(PetscBLASIntCast(m,&n));
     101           1 :   PetscCall(PetscMalloc1(m*m,&R));
     102             : 
     103             :   /* R = B+A*X */
     104          11 :   for (i=0;i<m;i++) PetscCall(PetscArraycpy(R+i*m,B+i*ldb,m));
     105           1 :   PetscCallBLAS("BLASgemm",BLASgemm_("N","N",&n,&n,&n,&done,A,&la,X,&lx,&done,R,&n));
     106             :   /* R = R+X*A' */
     107           1 :   PetscCallBLAS("BLASgemm",BLASgemm_("N","C",&n,&n,&n,&done,X,&lx,A,&la,&done,R,&n));
     108             : 
     109           1 :   *res = LAPACKlange_("F",&n,&n,R,&n,NULL);
     110           1 :   PetscCall(PetscFree(R));
     111           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     112             : }
     113             : #endif
     114             : 
     115             : #if defined(SLEPC_HAVE_SLICOT)
     116             : /*
     117             :    HessLyapunovChol_SLICOT - implementation used when SLICOT is available
     118             : */
     119             : static PetscErrorCode HessLyapunovChol_SLICOT(PetscInt m,PetscScalar *H,PetscInt ldh,PetscInt k,PetscScalar *B,PetscInt ldb,PetscScalar *U,PetscInt ldu,PetscReal *res)
     120             : {
     121             :   PetscBLASInt   lwork,info,n,kk,lu,ione=1,sdim;
     122             :   PetscInt       i,j;
     123             :   PetscReal      scal;
     124             :   PetscScalar    *Q,*W,*wr,*wi,*work;
     125             : 
     126             :   PetscFunctionBegin;
     127             :   PetscCall(PetscBLASIntCast(ldu,&lu));
     128             :   PetscCall(PetscBLASIntCast(m,&n));
     129             :   PetscCall(PetscBLASIntCast(k,&kk));
     130             :   PetscCall(PetscBLASIntCast(6*m,&lwork));
     131             :   PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
     132             : 
     133             :   /* transpose W = H' */
     134             :   PetscCall(PetscMalloc5(m*m,&W,m*m,&Q,m,&wr,m,&wi,lwork,&work));
     135             :   for (j=0;j<m;j++) {
     136             :     for (i=0;i<m;i++) W[i+j*m] = H[j+i*ldh];
     137             :   }
     138             : 
     139             :   /* compute the real Schur form of W */
     140             :   PetscCallBLAS("LAPACKgees",LAPACKgees_("V","N",NULL,&n,W,&n,&sdim,wr,wi,Q,&n,work,&lwork,NULL,&info));
     141             :   SlepcCheckLapackInfo("gees",info);
     142             : #if defined(PETSC_USE_DEBUG)
     143             :   for (i=0;i<m;i++) PetscCheck(PetscRealPart(wr[i])<0.0,PETSC_COMM_SELF,PETSC_ERR_USER_INPUT,"Eigenvalue with non-negative real part, the coefficient matrix is not stable");
     144             : #endif
     145             : 
     146             :   /* copy B' into first rows of U */
     147             :   for (i=0;i<k;i++) {
     148             :     for (j=0;j<m;j++) U[i+j*ldu] = B[j+i*ldb];
     149             :   }
     150             : 
     151             :   /* solve Lyapunov equation (Hammarling) */
     152             :   PetscCallBLAS("SLICOTsb03od",SLICOTsb03od_("C","F","N",&n,&kk,W,&n,Q,&n,U,&lu,&scal,wr,wi,work,&lwork,&info));
     153             :   PetscCheck(!info,PETSC_COMM_SELF,PETSC_ERR_LIB,"Error in SLICOT subroutine SB03OD: info=%" PetscBLASInt_FMT,info);
     154             :   PetscCheck(scal==1.0,PETSC_COMM_SELF,PETSC_ERR_SUP,"Current implementation cannot handle scale factor %g",scal);
     155             : 
     156             :   /* resnorm = norm(H(m+1,:)*U'*U), use Q(:,1) = U'*U(:,m) */
     157             :   if (res) {
     158             :     for (j=0;j<m;j++) Q[j] = U[j+(m-1)*ldu];
     159             :     PetscCallBLAS("BLAStrmv",BLAStrmv_("U","C","N",&n,U,&lu,Q,&ione));
     160             :     PetscCheck(k==1,PETSC_COMM_SELF,PETSC_ERR_LIB,"Residual error is intended for k=1 only, but you set k=%" PetscInt_FMT,k);
     161             :     *res *= BLASnrm2_(&n,Q,&ione);
     162             :   }
     163             : 
     164             :   PetscCall(PetscFPTrapPop());
     165             :   PetscCall(PetscFree5(W,Q,wr,wi,work));
     166             :   PetscFunctionReturn(PETSC_SUCCESS);
     167             : }
     168             : 
     169             : #else
     170             : 
     171             : /*
     172             :    Compute the upper Cholesky factor of A
     173             :  */
     174          60 : static PetscErrorCode CholeskyFactor(PetscInt m,PetscScalar *A,PetscInt lda)
     175             : {
     176          60 :   PetscInt       i;
     177          60 :   PetscScalar    *S;
     178          60 :   PetscBLASInt   info,n,ld;
     179             : 
     180          60 :   PetscFunctionBegin;
     181          60 :   PetscCall(PetscBLASIntCast(m,&n));
     182          60 :   PetscCall(PetscBLASIntCast(lda,&ld));
     183          60 :   PetscCall(PetscMalloc1(m*m,&S));
     184          60 :   PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
     185             : 
     186             :   /* save a copy of matrix in S */
     187        1852 :   for (i=0;i<m;i++) PetscCall(PetscArraycpy(S+i*m,A+i*lda,m));
     188             : 
     189             :   /* compute upper Cholesky factor in R */
     190          60 :   PetscCallBLAS("LAPACKpotrf",LAPACKpotrf_("U",&n,A,&ld,&info));
     191          60 :   PetscCall(PetscLogFlops((1.0*n*n*n)/3.0));
     192             : 
     193          60 :   if (info) {
     194        1841 :     for (i=0;i<m;i++) {
     195        1782 :       PetscCall(PetscArraycpy(A+i*lda,S+i*m,m));
     196        1782 :       A[i+i*lda] += 50.0*PETSC_MACHINE_EPSILON;
     197             :     }
     198          59 :     PetscCallBLAS("LAPACKpotrf",LAPACKpotrf_("U",&n,A,&ld,&info));
     199          59 :     SlepcCheckLapackInfo("potrf",info);
     200          59 :     PetscCall(PetscLogFlops((1.0*n*n*n)/3.0));
     201             :   }
     202             : 
     203             :   /* Zero out entries below the diagonal */
     204        1792 :   for (i=0;i<m-1;i++) PetscCall(PetscArrayzero(A+i*lda+i+1,m-i-1));
     205          60 :   PetscCall(PetscFPTrapPop());
     206          60 :   PetscCall(PetscFree(S));
     207          60 :   PetscFunctionReturn(PETSC_SUCCESS);
     208             : }
     209             : 
     210             : /*
     211             :    HessLyapunovChol_LAPACK - alternative implementation when SLICOT is not available
     212             : */
     213          60 : static PetscErrorCode HessLyapunovChol_LAPACK(PetscInt m,PetscScalar *H,PetscInt ldh,PetscInt k,PetscScalar *B,PetscInt ldb,PetscScalar *U,PetscInt ldu,PetscReal *res)
     214             : {
     215          60 :   PetscBLASInt   ilo=1,lwork,info,n,kk,lu,lb,ione=1;
     216          60 :   PetscInt       i,j;
     217          60 :   PetscReal      scal;
     218          60 :   PetscScalar    *Q,*C,*W,*Z,*wr,*work,zero=0.0,done=1.0,dmone=-1.0;
     219             : #if !defined(PETSC_USE_COMPLEX)
     220             :   PetscScalar    *wi;
     221             : #endif
     222             : 
     223          60 :   PetscFunctionBegin;
     224          60 :   PetscCall(PetscBLASIntCast(ldb,&lb));
     225          60 :   PetscCall(PetscBLASIntCast(ldu,&lu));
     226          60 :   PetscCall(PetscBLASIntCast(m,&n));
     227          60 :   PetscCall(PetscBLASIntCast(k,&kk));
     228          60 :   PetscCall(PetscBLASIntCast(6*m,&lwork));
     229          60 :   PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
     230          60 :   C = U;
     231             : 
     232             : #if !defined(PETSC_USE_COMPLEX)
     233             :   PetscCall(PetscMalloc6(m*m,&Q,m*m,&W,m*k,&Z,m,&wr,m,&wi,lwork,&work));
     234             : #else
     235          60 :   PetscCall(PetscMalloc5(m*m,&Q,m*m,&W,m*k,&Z,m,&wr,lwork,&work));
     236             : #endif
     237             : 
     238             :   /* save a copy W = H */
     239        1852 :   for (j=0;j<m;j++) {
     240       56612 :     for (i=0;i<m;i++) W[i+j*m] = H[i+j*ldh];
     241             :   }
     242             : 
     243             :   /* compute the (real) Schur form of W */
     244             : #if !defined(PETSC_USE_COMPLEX)
     245             :   PetscCallBLAS("LAPACKhseqr",LAPACKhseqr_("S","I",&n,&ilo,&n,W,&n,wr,wi,Q,&n,work,&lwork,&info));
     246             : #else
     247          60 :   PetscCallBLAS("LAPACKhseqr",LAPACKhseqr_("S","I",&n,&ilo,&n,W,&n,wr,Q,&n,work,&lwork,&info));
     248             : #endif
     249          60 :   SlepcCheckLapackInfo("hseqr",info);
     250             : #if defined(PETSC_USE_DEBUG)
     251        1852 :   for (i=0;i<m;i++) PetscCheck(PetscRealPart(wr[i])<0.0,PETSC_COMM_SELF,PETSC_ERR_USER_INPUT,"Eigenvalue with non-negative real part %g, the coefficient matrix is not stable",(double)PetscRealPart(wr[i]));
     252             : #endif
     253             : 
     254             :   /* C = -Z*Z', Z = Q'*B */
     255          60 :   PetscCallBLAS("BLASgemm",BLASgemm_("C","N",&n,&kk,&n,&done,Q,&n,B,&lb,&zero,Z,&n));
     256          60 :   PetscCallBLAS("BLASgemm",BLASgemm_("N","C",&n,&n,&kk,&dmone,Z,&n,Z,&n,&zero,C,&lu));
     257             : 
     258             :   /* solve triangular Sylvester equation */
     259          60 :   PetscCallBLAS("LAPACKtrsyl",LAPACKtrsyl_("N","C",&ione,&n,&n,W,&n,W,&n,C,&lu,&scal,&info));
     260          60 :   SlepcCheckLapackInfo("trsyl",info);
     261          60 :   PetscCheck(scal==1.0,PETSC_COMM_SELF,PETSC_ERR_SUP,"Current implementation cannot handle scale factor %g",(double)scal);
     262             : 
     263             :   /* back-transform C = Q*C*Q' */
     264          60 :   PetscCallBLAS("BLASgemm",BLASgemm_("N","N",&n,&n,&n,&done,Q,&n,C,&n,&zero,W,&n));
     265          60 :   PetscCallBLAS("BLASgemm",BLASgemm_("N","C",&n,&n,&n,&done,W,&n,Q,&n,&zero,C,&lu));
     266             : 
     267             :   /* resnorm = norm(H(m+1,:)*Y) */
     268          60 :   if (res) {
     269          59 :     PetscCheck(k==1,PETSC_COMM_SELF,PETSC_ERR_LIB,"Residual error is intended for k=1 only, but you set k=%" PetscInt_FMT,k);
     270          59 :     *res *= BLASnrm2_(&n,C+m-1,&n);
     271             :   }
     272             : 
     273             :   /* U = chol(C) */
     274          60 :   PetscCall(CholeskyFactor(m,C,ldu));
     275             : 
     276          60 :   PetscCall(PetscFPTrapPop());
     277             : #if !defined(PETSC_USE_COMPLEX)
     278             :   PetscCall(PetscFree6(Q,W,Z,wr,wi,work));
     279             : #else
     280          60 :   PetscCall(PetscFree5(Q,W,Z,wr,work));
     281             : #endif
     282          60 :   PetscFunctionReturn(PETSC_SUCCESS);
     283             : }
     284             : 
     285             : #endif /* SLEPC_HAVE_SLICOT */
     286             : 
     287             : /*@C
     288             :    LMEDenseHessLyapunovChol - Computes the Cholesky factor of the solution of a
     289             :    dense Lyapunov equation with an upper Hessenberg coefficient matrix.
     290             : 
     291             :    Logically Collective
     292             : 
     293             :    Input Parameters:
     294             : +  lme - linear matrix equation solver context
     295             : .  m   - number of rows and columns of H
     296             : .  H   - coefficient matrix
     297             : .  ldh - leading dimension of H
     298             : .  k   - number of columns of B
     299             : .  B   - right-hand side matrix
     300             : .  ldb - leading dimension of B
     301             : -  ldu - leading dimension of U
     302             : 
     303             :    Output Parameters:
     304             : +  U   - Cholesky factor of the solution
     305             : -  res - (optional) residual norm, on input it should contain H(m+1,m)
     306             : 
     307             :    Note:
     308             :    The Lyapunov equation has the form H*X + X*H' = -B*B', where H is an mxm
     309             :    upper Hessenberg matrix, B is an mxk matrix and the solution is expressed
     310             :    as X = U'*U, where U is upper triangular. H is supposed to be stable.
     311             : 
     312             :    When k=1 and the res argument is provided, the last row of X is used to
     313             :    compute the residual norm of a Lyapunov equation projected via Arnoldi.
     314             : 
     315             :    Level: developer
     316             : 
     317             : .seealso: LMEDenseLyapunov(), LMESolve()
     318             : @*/
     319          60 : PetscErrorCode LMEDenseHessLyapunovChol(LME lme,PetscInt m,PetscScalar *H,PetscInt ldh,PetscInt k,PetscScalar *B,PetscInt ldb,PetscScalar *U,PetscInt ldu,PetscReal *res)
     320             : {
     321             : #if defined(PETSC_USE_INFO)
     322          60 :   PetscReal      error;
     323             : #endif
     324             : 
     325          60 :   PetscFunctionBegin;
     326          60 :   PetscValidHeaderSpecific(lme,LME_CLASSID,1);
     327         180 :   PetscValidLogicalCollectiveInt(lme,m,2);
     328          60 :   PetscAssertPointer(H,3);
     329         180 :   PetscValidLogicalCollectiveInt(lme,ldh,4);
     330         180 :   PetscValidLogicalCollectiveInt(lme,k,5);
     331          60 :   PetscAssertPointer(B,6);
     332         180 :   PetscValidLogicalCollectiveInt(lme,ldb,7);
     333          60 :   PetscAssertPointer(U,8);
     334         180 :   PetscValidLogicalCollectiveInt(lme,ldu,9);
     335         178 :   if (res) PetscValidLogicalCollectiveReal(lme,*res,10);
     336             : 
     337             : #if defined(SLEPC_HAVE_SLICOT)
     338             :   PetscCall(HessLyapunovChol_SLICOT(m,H,ldh,k,B,ldb,U,ldu,res));
     339             : #else
     340          60 :   PetscCall(HessLyapunovChol_LAPACK(m,H,ldh,k,B,ldb,U,ldu,res));
     341             : #endif
     342             : 
     343             : #if defined(PETSC_USE_INFO)
     344          60 :   if (PetscLogPrintInfo) {
     345           1 :     PetscCall(LyapunovCholResidual(m,H,ldh,k,B,ldb,U,ldu,&error));
     346           1 :     PetscCall(PetscInfo(lme,"Residual norm of dense Lyapunov equation = %g\n",(double)error));
     347             :   }
     348             : #endif
     349          60 :   PetscFunctionReturn(PETSC_SUCCESS);
     350             : }
     351             : 
     352             : #if defined(SLEPC_HAVE_SLICOT)
     353             : /*
     354             :    Lyapunov_SLICOT - implementation used when SLICOT is available
     355             : */
     356             : static PetscErrorCode Lyapunov_SLICOT(PetscInt m,PetscScalar *H,PetscInt ldh,PetscScalar *B,PetscInt ldb,PetscScalar *X,PetscInt ldx)
     357             : {
     358             :   PetscBLASInt   sdim,lwork,info,n,lx,*iwork;
     359             :   PetscInt       i,j;
     360             :   PetscReal      scal,sep,ferr,*work;
     361             :   PetscScalar    *Q,*W,*wr,*wi;
     362             : 
     363             :   PetscFunctionBegin;
     364             :   PetscCall(PetscBLASIntCast(ldx,&lx));
     365             :   PetscCall(PetscBLASIntCast(m,&n));
     366             :   PetscCall(PetscBLASIntCast(PetscMax(20,m*m),&lwork));
     367             :   PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
     368             : 
     369             :   /* transpose W = H' */
     370             :   PetscCall(PetscMalloc6(m*m,&W,m*m,&Q,m,&wr,m,&wi,m*m,&iwork,lwork,&work));
     371             :   for (j=0;j<m;j++) {
     372             :     for (i=0;i<m;i++) W[i+j*m] = H[j+i*ldh];
     373             :   }
     374             : 
     375             :   /* compute the real Schur form of W */
     376             :   PetscCallBLAS("LAPACKgees",LAPACKgees_("V","N",NULL,&n,W,&n,&sdim,wr,wi,Q,&n,work,&lwork,NULL,&info));
     377             :   SlepcCheckLapackInfo("gees",info);
     378             : 
     379             :   /* copy -B into X */
     380             :   for (i=0;i<m;i++) {
     381             :     for (j=0;j<m;j++) X[i+j*ldx] = -B[i+j*ldb];
     382             :   }
     383             : 
     384             :   /* solve Lyapunov equation (Hammarling) */
     385             :   PetscCallBLAS("SLICOTsb03md",SLICOTsb03md_("C","X","F","N",&n,W,&n,Q,&n,X,&lx,&scal,&sep,&ferr,wr,wi,iwork,work,&lwork,&info));
     386             :   PetscCheck(!info,PETSC_COMM_SELF,PETSC_ERR_LIB,"Error in SLICOT subroutine SB03OD: info=%" PetscBLASInt_FMT,info);
     387             :   PetscCheck(scal==1.0,PETSC_COMM_SELF,PETSC_ERR_SUP,"Current implementation cannot handle scale factor %g",scal);
     388             : 
     389             :   PetscCall(PetscFPTrapPop());
     390             :   PetscCall(PetscFree6(W,Q,wr,wi,iwork,work));
     391             :   PetscFunctionReturn(PETSC_SUCCESS);
     392             : }
     393             : 
     394             : #else
     395             : 
     396             : /*
     397             :    Lyapunov_LAPACK - alternative implementation when SLICOT is not available
     398             : */
     399           1 : static PetscErrorCode Lyapunov_LAPACK(PetscInt m,PetscScalar *A,PetscInt lda,PetscScalar *B,PetscInt ldb,PetscScalar *X,PetscInt ldx)
     400             : {
     401           1 :   PetscBLASInt   sdim,lwork,info,n,lx,lb,ione=1;
     402           1 :   PetscInt       i,j;
     403           1 :   PetscReal      scal;
     404           1 :   PetscScalar    *Q,*W,*Z,*wr,*work,zero=0.0,done=1.0,dmone=-1.0;
     405             : #if defined(PETSC_USE_COMPLEX)
     406           1 :   PetscReal      *rwork;
     407             : #else
     408             :   PetscScalar    *wi;
     409             : #endif
     410             : 
     411           1 :   PetscFunctionBegin;
     412           1 :   PetscCall(PetscBLASIntCast(ldb,&lb));
     413           1 :   PetscCall(PetscBLASIntCast(ldx,&lx));
     414           1 :   PetscCall(PetscBLASIntCast(m,&n));
     415           1 :   PetscCall(PetscBLASIntCast(6*m,&lwork));
     416           1 :   PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
     417             : 
     418             : #if !defined(PETSC_USE_COMPLEX)
     419             :   PetscCall(PetscMalloc6(m*m,&Q,m*m,&W,m*m,&Z,m,&wr,m,&wi,lwork,&work));
     420             : #else
     421           1 :   PetscCall(PetscMalloc6(m*m,&Q,m*m,&W,m*m,&Z,m,&wr,lwork,&work,m,&rwork));
     422             : #endif
     423             : 
     424             :   /* save a copy W = A */
     425          11 :   for (j=0;j<m;j++) {
     426         110 :     for (i=0;i<m;i++) W[i+j*m] = A[i+j*lda];
     427             :   }
     428             : 
     429             :   /* compute the (real) Schur form of W */
     430             : #if !defined(PETSC_USE_COMPLEX)
     431             :   PetscCallBLAS("LAPACKgees",LAPACKgees_("V","N",NULL,&n,W,&n,&sdim,wr,wi,Q,&n,work,&lwork,NULL,&info));
     432             : #else
     433           1 :   PetscCallBLAS("LAPACKgees",LAPACKgees_("V","N",NULL,&n,W,&n,&sdim,wr,Q,&n,work,&lwork,rwork,NULL,&info));
     434             : #endif
     435           1 :   SlepcCheckLapackInfo("gees",info);
     436             : 
     437             :   /* X = -Q'*B*Q */
     438           1 :   PetscCallBLAS("BLASgemm",BLASgemm_("C","N",&n,&n,&n,&done,Q,&n,B,&lb,&zero,Z,&n));
     439           1 :   PetscCallBLAS("BLASgemm",BLASgemm_("N","N",&n,&n,&n,&dmone,Z,&n,Q,&n,&zero,X,&lx));
     440             : 
     441             :   /* solve triangular Sylvester equation */
     442           1 :   PetscCallBLAS("LAPACKtrsyl",LAPACKtrsyl_("N","C",&ione,&n,&n,W,&n,W,&n,X,&lx,&scal,&info));
     443           1 :   SlepcCheckLapackInfo("trsyl",info);
     444           1 :   PetscCheck(scal==1.0,PETSC_COMM_SELF,PETSC_ERR_SUP,"Current implementation cannot handle scale factor %g",(double)scal);
     445             : 
     446             :   /* back-transform X = Q*X*Q' */
     447           1 :   PetscCallBLAS("BLASgemm",BLASgemm_("N","N",&n,&n,&n,&done,Q,&n,X,&n,&zero,W,&n));
     448           1 :   PetscCallBLAS("BLASgemm",BLASgemm_("N","C",&n,&n,&n,&done,W,&n,Q,&n,&zero,X,&lx));
     449             : 
     450           1 :   PetscCall(PetscFPTrapPop());
     451             : #if !defined(PETSC_USE_COMPLEX)
     452             :   PetscCall(PetscFree6(Q,W,Z,wr,wi,work));
     453             : #else
     454           1 :   PetscCall(PetscFree6(Q,W,Z,wr,work,rwork));
     455             : #endif
     456           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     457             : }
     458             : 
     459             : #endif /* SLEPC_HAVE_SLICOT */
     460             : 
     461             : /*@C
     462             :    LMEDenseLyapunov - Computes the solution of a dense continuous-time Lyapunov
     463             :    equation.
     464             : 
     465             :    Logically Collective
     466             : 
     467             :    Input Parameters:
     468             : +  lme - linear matrix equation solver context
     469             : .  m   - number of rows and columns of A
     470             : .  A   - coefficient matrix
     471             : .  lda - leading dimension of A
     472             : .  B   - right-hand side matrix
     473             : .  ldb - leading dimension of B
     474             : -  ldx - leading dimension of X
     475             : 
     476             :    Output Parameter:
     477             : .  X   - the solution
     478             : 
     479             :    Note:
     480             :    The Lyapunov equation has the form A*X + X*A' = -B, where all are mxm
     481             :    matrices, and B is symmetric.
     482             : 
     483             :    Level: developer
     484             : 
     485             : .seealso: LMEDenseHessLyapunovChol(), LMESolve()
     486             : @*/
     487           1 : PetscErrorCode LMEDenseLyapunov(LME lme,PetscInt m,PetscScalar *A,PetscInt lda,PetscScalar *B,PetscInt ldb,PetscScalar *X,PetscInt ldx)
     488             : {
     489             : #if defined(PETSC_USE_INFO)
     490           1 :   PetscReal      error;
     491             : #endif
     492             : 
     493           1 :   PetscFunctionBegin;
     494           1 :   PetscValidHeaderSpecific(lme,LME_CLASSID,1);
     495           3 :   PetscValidLogicalCollectiveInt(lme,m,2);
     496           1 :   PetscAssertPointer(A,3);
     497           3 :   PetscValidLogicalCollectiveInt(lme,lda,4);
     498           1 :   PetscAssertPointer(B,5);
     499           3 :   PetscValidLogicalCollectiveInt(lme,ldb,6);
     500           1 :   PetscAssertPointer(X,7);
     501           3 :   PetscValidLogicalCollectiveInt(lme,ldx,8);
     502             : 
     503             : #if defined(SLEPC_HAVE_SLICOT)
     504             :   PetscCall(Lyapunov_SLICOT(m,A,lda,B,ldb,X,ldx));
     505             : #else
     506           1 :   PetscCall(Lyapunov_LAPACK(m,A,lda,B,ldb,X,ldx));
     507             : #endif
     508             : 
     509             : #if defined(PETSC_USE_INFO)
     510           1 :   if (PetscLogPrintInfo) {
     511           1 :     PetscCall(LyapunovResidual(m,A,lda,B,ldb,X,ldx,&error));
     512           1 :     PetscCall(PetscInfo(lme,"Residual norm of dense Lyapunov equation = %g\n",(double)error));
     513             :   }
     514             : #endif
     515           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     516             : }

Generated by: LCOV version 1.14