LCOV - code coverage report
Current view: top level - sys/classes/ds/impls/nhep - dsnhep.c (source / functions) Hit Total Coverage
Test: SLEPc Lines: 357 366 97.5 %
Date: 2024-04-18 01:01:30 Functions: 17 17 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             : #include <slepc/private/dsimpl.h>
      12             : #include <slepcblaslapack.h>
      13             : 
      14         386 : static PetscErrorCode DSAllocate_NHEP(DS ds,PetscInt ld)
      15             : {
      16         386 :   PetscFunctionBegin;
      17         386 :   PetscCall(DSAllocateMat_Private(ds,DS_MAT_A));
      18         386 :   PetscCall(DSAllocateMat_Private(ds,DS_MAT_Q));
      19         386 :   PetscCall(PetscFree(ds->perm));
      20         386 :   PetscCall(PetscMalloc1(ld,&ds->perm));
      21         386 :   PetscFunctionReturn(PETSC_SUCCESS);
      22             : }
      23             : 
      24          11 : static PetscErrorCode DSView_NHEP(DS ds,PetscViewer viewer)
      25             : {
      26          11 :   PetscViewerFormat format;
      27             : 
      28          11 :   PetscFunctionBegin;
      29          11 :   PetscCall(PetscViewerGetFormat(viewer,&format));
      30          11 :   if (format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL) PetscFunctionReturn(PETSC_SUCCESS);
      31           0 :   PetscCall(DSViewMat(ds,viewer,DS_MAT_A));
      32           0 :   if (ds->state>DS_STATE_INTERMEDIATE) PetscCall(DSViewMat(ds,viewer,DS_MAT_Q));
      33           0 :   if (ds->omat[DS_MAT_X]) PetscCall(DSViewMat(ds,viewer,DS_MAT_X));
      34           0 :   if (ds->omat[DS_MAT_Y]) PetscCall(DSViewMat(ds,viewer,DS_MAT_Y));
      35           0 :   PetscFunctionReturn(PETSC_SUCCESS);
      36             : }
      37             : 
      38          54 : static PetscErrorCode DSVectors_NHEP_Refined_Some(DS ds,PetscInt *k,PetscReal *rnorm,PetscBool left)
      39             : {
      40          54 :   PetscInt          i,j;
      41          54 :   PetscBLASInt      info,ld,n,n1,lwork,inc=1;
      42          54 :   PetscScalar       sdummy,done=1.0,zero=0.0;
      43          54 :   PetscReal         *sigma;
      44          54 :   PetscBool         iscomplex = PETSC_FALSE;
      45          54 :   PetscScalar       *X,*W;
      46          54 :   const PetscScalar *A,*Q;
      47             : 
      48          54 :   PetscFunctionBegin;
      49          54 :   PetscCheck(!left,PetscObjectComm((PetscObject)ds),PETSC_ERR_SUP,"Not implemented for left vectors");
      50          54 :   PetscCall(PetscBLASIntCast(ds->n,&n));
      51          54 :   PetscCall(PetscBLASIntCast(ds->ld,&ld));
      52          54 :   n1 = n+1;
      53          54 :   PetscCall(DSAllocateWork_Private(ds,5*ld,6*ld,0));
      54          54 :   PetscCall(DSAllocateMat_Private(ds,DS_MAT_W));
      55          54 :   lwork = 5*ld;
      56          54 :   sigma = ds->rwork+5*ld;
      57             : 
      58             :   /* build A-w*I in W */
      59          54 :   PetscCall(MatDenseGetArrayRead(ds->omat[DS_MAT_A],&A));
      60          54 :   PetscCall(MatDenseGetArrayWrite(ds->omat[DS_MAT_W],&W));
      61          54 :   if ((*k)<n-1 && A[(*k)+1+(*k)*ld]!=0.0) iscomplex = PETSC_TRUE;
      62          54 :   PetscCheck(!iscomplex,PETSC_COMM_SELF,PETSC_ERR_SUP,"Not implemented for complex eigenvalues yet");
      63        2281 :   for (j=0;j<n;j++)
      64       97947 :     for (i=0;i<=n;i++)
      65       95720 :       W[i+j*ld] = A[i+j*ld];
      66        2281 :   for (i=0;i<n;i++)
      67        2227 :     W[i+i*ld] -= A[(*k)+(*k)*ld];
      68          54 :   PetscCall(MatDenseRestoreArrayRead(ds->omat[DS_MAT_A],&A));
      69             : 
      70             :   /* compute SVD of W */
      71             : #if !defined(PETSC_USE_COMPLEX)
      72          54 :   PetscCallBLAS("LAPACKgesvd",LAPACKgesvd_("N","O",&n1,&n,W,&ld,sigma,&sdummy,&ld,&sdummy,&ld,ds->work,&lwork,&info));
      73             : #else
      74             :   PetscCallBLAS("LAPACKgesvd",LAPACKgesvd_("N","O",&n1,&n,W,&ld,sigma,&sdummy,&ld,&sdummy,&ld,ds->work,&lwork,ds->rwork,&info));
      75             : #endif
      76          54 :   SlepcCheckLapackInfo("gesvd",info);
      77             : 
      78             :   /* the smallest singular value is the new error estimate */
      79          54 :   if (rnorm) *rnorm = sigma[n-1];
      80             : 
      81             :   /* update vector with right singular vector associated to smallest singular value,
      82             :      accumulating the transformation matrix Q */
      83          54 :   PetscCall(MatDenseGetArrayRead(ds->omat[DS_MAT_Q],&Q));
      84         108 :   PetscCall(MatDenseGetArray(ds->omat[left?DS_MAT_Y:DS_MAT_X],&X));
      85          54 :   PetscCallBLAS("BLASgemv",BLASgemv_("N",&n,&n,&done,Q,&ld,W+n-1,&ld,&zero,X+(*k)*ld,&inc));
      86          54 :   PetscCall(MatDenseRestoreArrayRead(ds->omat[DS_MAT_Q],&Q));
      87          54 :   PetscCall(MatDenseRestoreArray(ds->omat[left?DS_MAT_Y:DS_MAT_X],&X));
      88          54 :   PetscCall(MatDenseRestoreArrayWrite(ds->omat[DS_MAT_W],&W));
      89          54 :   PetscFunctionReturn(PETSC_SUCCESS);
      90             : }
      91             : 
      92           1 : static PetscErrorCode DSVectors_NHEP_Refined_All(DS ds,PetscBool left)
      93             : {
      94           1 :   PetscInt       i;
      95             : 
      96           1 :   PetscFunctionBegin;
      97           2 :   for (i=0;i<ds->n;i++) PetscCall(DSVectors_NHEP_Refined_Some(ds,&i,NULL,left));
      98           1 :   PetscFunctionReturn(PETSC_SUCCESS);
      99             : }
     100             : 
     101        6089 : static PetscErrorCode DSVectors_NHEP_Eigen_Some(DS ds,PetscInt *k,PetscReal *rnorm,PetscBool left)
     102             : {
     103        6089 :   PetscInt          i;
     104        6089 :   PetscBLASInt      mm=1,mout,info,ld,n,*select,inc=1,cols=1,zero=0;
     105        6089 :   PetscScalar       sone=1.0,szero=0.0;
     106        6089 :   PetscReal         norm,done=1.0;
     107        6089 :   PetscBool         iscomplex = PETSC_FALSE;
     108        6089 :   PetscScalar       *X,*Y;
     109        6089 :   const PetscScalar *A,*Q;
     110             : 
     111        6089 :   PetscFunctionBegin;
     112        6089 :   PetscCall(PetscBLASIntCast(ds->n,&n));
     113        6089 :   PetscCall(PetscBLASIntCast(ds->ld,&ld));
     114        6089 :   PetscCall(DSAllocateWork_Private(ds,0,0,ld));
     115        6089 :   select = ds->iwork;
     116      141883 :   for (i=0;i<n;i++) select[i] = (PetscBLASInt)PETSC_FALSE;
     117             : 
     118             :   /* compute k-th eigenvector Y of A */
     119        6089 :   PetscCall(MatDenseGetArrayRead(ds->omat[DS_MAT_A],&A));
     120       11863 :   PetscCall(MatDenseGetArray(ds->omat[left?DS_MAT_Y:DS_MAT_X],&X));
     121        6089 :   Y = X+(*k)*ld;
     122        6089 :   select[*k] = (PetscBLASInt)PETSC_TRUE;
     123             : #if !defined(PETSC_USE_COMPLEX)
     124        6089 :   if ((*k)<n-1 && A[(*k)+1+(*k)*ld]!=0.0) iscomplex = PETSC_TRUE;
     125        6089 :   mm = iscomplex? 2: 1;
     126        6089 :   if (iscomplex) select[(*k)+1] = (PetscBLASInt)PETSC_TRUE;
     127        6089 :   PetscCall(DSAllocateWork_Private(ds,3*ld,0,0));
     128       11863 :   PetscCallBLAS("LAPACKtrevc",LAPACKtrevc_(left?"L":"R","S",select,&n,(PetscScalar*)A,&ld,Y,&ld,Y,&ld,&mm,&mout,ds->work,&info));
     129             : #else
     130             :   PetscCall(DSAllocateWork_Private(ds,2*ld,ld,0));
     131             :   PetscCallBLAS("LAPACKtrevc",LAPACKtrevc_(left?"L":"R","S",select,&n,(PetscScalar*)A,&ld,Y,&ld,Y,&ld,&mm,&mout,ds->work,ds->rwork,&info));
     132             : #endif
     133        6089 :   SlepcCheckLapackInfo("trevc",info);
     134        6089 :   PetscCheck(mout==mm,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Inconsistent arguments");
     135        6089 :   PetscCall(MatDenseRestoreArrayRead(ds->omat[DS_MAT_A],&A));
     136             : 
     137             :   /* accumulate and normalize eigenvectors */
     138        6089 :   if (ds->state>=DS_STATE_CONDENSED) {
     139        6089 :     PetscCall(MatDenseGetArrayRead(ds->omat[DS_MAT_Q],&Q));
     140        6089 :     PetscCall(PetscArraycpy(ds->work,Y,mout*ld));
     141        6089 :     PetscCallBLAS("BLASgemv",BLASgemv_("N",&n,&n,&sone,Q,&ld,ds->work,&inc,&szero,Y,&inc));
     142             : #if !defined(PETSC_USE_COMPLEX)
     143        6089 :     if (iscomplex) PetscCallBLAS("BLASgemv",BLASgemv_("N",&n,&n,&sone,Q,&ld,ds->work+ld,&inc,&szero,Y+ld,&inc));
     144             : #endif
     145        6089 :     PetscCall(MatDenseRestoreArrayRead(ds->omat[DS_MAT_Q],&Q));
     146        6089 :     cols = 1;
     147        6089 :     norm = BLASnrm2_(&n,Y,&inc);
     148             : #if !defined(PETSC_USE_COMPLEX)
     149        6089 :     if (iscomplex) {
     150         637 :       norm = SlepcAbsEigenvalue(norm,BLASnrm2_(&n,Y+ld,&inc));
     151         637 :       cols = 2;
     152             :     }
     153             : #endif
     154        6089 :     PetscCallBLAS("LAPACKlascl",LAPACKlascl_("G",&zero,&zero,&norm,&done,&n,&cols,Y,&ld,&info));
     155        6089 :     SlepcCheckLapackInfo("lascl",info);
     156             :   }
     157             : 
     158             :   /* set output arguments */
     159        6089 :   if (iscomplex) (*k)++;
     160        6089 :   if (rnorm) {
     161        5084 :     if (iscomplex) *rnorm = SlepcAbsEigenvalue(Y[n-1],Y[n-1+ld]);
     162        4451 :     else *rnorm = PetscAbsScalar(Y[n-1]);
     163             :   }
     164        6089 :   PetscCall(MatDenseRestoreArray(ds->omat[left?DS_MAT_Y:DS_MAT_X],&X));
     165        6089 :   PetscFunctionReturn(PETSC_SUCCESS);
     166             : }
     167             : 
     168         458 : static PetscErrorCode DSVectors_NHEP_Eigen_All(DS ds,PetscBool left)
     169             : {
     170         458 :   PetscInt          i;
     171         458 :   PetscBLASInt      n,ld,mout,info,inc=1,cols,zero=0;
     172         458 :   PetscBool         iscomplex;
     173         458 :   PetscScalar       *X,*Y,*Z;
     174         458 :   const PetscScalar *A,*Q;
     175         458 :   PetscReal         norm,done=1.0;
     176         458 :   const char        *side,*back;
     177             : 
     178         458 :   PetscFunctionBegin;
     179         458 :   PetscCall(MatDenseGetArrayRead(ds->omat[DS_MAT_A],&A));
     180         458 :   PetscCall(PetscBLASIntCast(ds->n,&n));
     181         458 :   PetscCall(PetscBLASIntCast(ds->ld,&ld));
     182         458 :   if (left) {
     183           1 :     X = NULL;
     184           1 :     PetscCall(MatDenseGetArray(ds->omat[DS_MAT_Y],&Y));
     185             :     side = "L";
     186             :   } else {
     187         457 :     PetscCall(MatDenseGetArray(ds->omat[DS_MAT_X],&X));
     188         457 :     Y = NULL;
     189         457 :     side = "R";
     190             :   }
     191         458 :   Z = left? Y: X;
     192         458 :   if (ds->state>=DS_STATE_CONDENSED) {
     193             :     /* DSSolve() has been called, backtransform with matrix Q */
     194          94 :     back = "B";
     195          94 :     PetscCall(MatDenseGetArrayRead(ds->omat[DS_MAT_Q],&Q));
     196          94 :     PetscCall(PetscArraycpy(Z,Q,ld*ld));
     197          94 :     PetscCall(MatDenseRestoreArrayRead(ds->omat[DS_MAT_Q],&Q));
     198             :   } else back = "A";
     199             : #if !defined(PETSC_USE_COMPLEX)
     200         458 :   PetscCall(DSAllocateWork_Private(ds,3*ld,0,0));
     201         458 :   PetscCallBLAS("LAPACKtrevc",LAPACKtrevc_(side,back,NULL,&n,(PetscScalar*)A,&ld,Y,&ld,X,&ld,&n,&mout,ds->work,&info));
     202             : #else
     203             :   PetscCall(DSAllocateWork_Private(ds,2*ld,ld,0));
     204             :   PetscCallBLAS("LAPACKtrevc",LAPACKtrevc_(side,back,NULL,&n,(PetscScalar*)A,&ld,Y,&ld,X,&ld,&n,&mout,ds->work,ds->rwork,&info));
     205             : #endif
     206         458 :   SlepcCheckLapackInfo("trevc",info);
     207             : 
     208             :   /* normalize eigenvectors */
     209        4084 :   for (i=0;i<n;i++) {
     210        3626 :     iscomplex = (i<n-1 && A[i+1+i*ld]!=0.0)? PETSC_TRUE: PETSC_FALSE;
     211        3626 :     cols = 1;
     212        3626 :     norm = BLASnrm2_(&n,Z+i*ld,&inc);
     213             : #if !defined(PETSC_USE_COMPLEX)
     214        3626 :     if (iscomplex) {
     215         252 :       norm = SlepcAbsEigenvalue(norm,BLASnrm2_(&n,Z+(i+1)*ld,&inc));
     216         252 :       cols = 2;
     217             :     }
     218             : #endif
     219        3626 :     PetscCallBLAS("LAPACKlascl",LAPACKlascl_("G",&zero,&zero,&norm,&done,&n,&cols,Z+i*ld,&ld,&info));
     220        3626 :     SlepcCheckLapackInfo("lascl",info);
     221        3626 :     if (iscomplex) i++;
     222             :   }
     223         458 :   PetscCall(MatDenseRestoreArrayRead(ds->omat[DS_MAT_A],&A));
     224         915 :   PetscCall(MatDenseRestoreArray(ds->omat[left?DS_MAT_Y:DS_MAT_X],&Z));
     225         458 :   PetscFunctionReturn(PETSC_SUCCESS);
     226             : }
     227             : 
     228        6601 : static PetscErrorCode DSVectors_NHEP(DS ds,DSMatType mat,PetscInt *j,PetscReal *rnorm)
     229             : {
     230        6601 :   PetscFunctionBegin;
     231        6601 :   switch (mat) {
     232        6285 :     case DS_MAT_X:
     233        6285 :       if (ds->refined) {
     234          54 :         PetscCheck(ds->extrarow,PetscObjectComm((PetscObject)ds),PETSC_ERR_SUP,"Refined vectors require activating the extra row");
     235          54 :         if (j) PetscCall(DSVectors_NHEP_Refined_Some(ds,j,rnorm,PETSC_FALSE));
     236           1 :         else PetscCall(DSVectors_NHEP_Refined_All(ds,PETSC_FALSE));
     237             :       } else {
     238        6231 :         if (j) PetscCall(DSVectors_NHEP_Eigen_Some(ds,j,rnorm,PETSC_FALSE));
     239         457 :         else PetscCall(DSVectors_NHEP_Eigen_All(ds,PETSC_FALSE));
     240             :       }
     241             :       break;
     242         316 :     case DS_MAT_Y:
     243         316 :       PetscCheck(!ds->refined,PetscObjectComm((PetscObject)ds),PETSC_ERR_SUP,"Not implemented yet");
     244         316 :       if (j) PetscCall(DSVectors_NHEP_Eigen_Some(ds,j,rnorm,PETSC_TRUE));
     245           1 :       else PetscCall(DSVectors_NHEP_Eigen_All(ds,PETSC_TRUE));
     246             :       break;
     247           0 :     case DS_MAT_U:
     248             :     case DS_MAT_V:
     249           0 :       SETERRQ(PetscObjectComm((PetscObject)ds),PETSC_ERR_SUP,"Not implemented yet");
     250           0 :     default:
     251           0 :       SETERRQ(PetscObjectComm((PetscObject)ds),PETSC_ERR_ARG_OUTOFRANGE,"Invalid mat parameter");
     252             :   }
     253        6601 :   PetscFunctionReturn(PETSC_SUCCESS);
     254             : }
     255             : 
     256          17 : static PetscErrorCode DSSort_NHEP_Arbitrary(DS ds,PetscScalar *wr,PetscScalar *wi,PetscScalar *rr,PetscScalar *ri,PetscInt *k)
     257             : {
     258          17 :   PetscInt       i;
     259          17 :   PetscBLASInt   info,n,ld,mout,lwork,*selection;
     260          17 :   PetscScalar    *T,*Q,*work;
     261          17 :   PetscReal      dummy;
     262             : #if !defined(PETSC_USE_COMPLEX)
     263          17 :   PetscBLASInt   *iwork,liwork;
     264             : #endif
     265             : 
     266          17 :   PetscFunctionBegin;
     267          17 :   PetscCheck(k,PetscObjectComm((PetscObject)ds),PETSC_ERR_ARG_WRONG,"Must supply argument k");
     268          17 :   PetscCall(MatDenseGetArray(ds->omat[DS_MAT_A],&T));
     269          17 :   PetscCall(MatDenseGetArray(ds->omat[DS_MAT_Q],&Q));
     270          17 :   PetscCall(PetscBLASIntCast(ds->n,&n));
     271          17 :   PetscCall(PetscBLASIntCast(ds->ld,&ld));
     272             : #if !defined(PETSC_USE_COMPLEX)
     273          17 :   lwork = n;
     274          17 :   liwork = 1;
     275          17 :   PetscCall(DSAllocateWork_Private(ds,lwork,0,liwork+n));
     276          17 :   work = ds->work;
     277          17 :   lwork = ds->lwork;
     278          17 :   selection = ds->iwork;
     279          17 :   iwork = ds->iwork + n;
     280          17 :   liwork = ds->liwork - n;
     281             : #else
     282             :   lwork = 1;
     283             :   PetscCall(DSAllocateWork_Private(ds,lwork,0,n));
     284             :   work = ds->work;
     285             :   selection = ds->iwork;
     286             : #endif
     287             :   /* Compute the selected eigenvalue to be in the leading position */
     288          17 :   PetscCall(DSSortEigenvalues_Private(ds,rr,ri,ds->perm,PETSC_FALSE));
     289          17 :   PetscCall(PetscArrayzero(selection,n));
     290          61 :   for (i=0;i<*k;i++) selection[ds->perm[i]] = 1;
     291             : #if !defined(PETSC_USE_COMPLEX)
     292          17 :   PetscCallBLAS("LAPACKtrsen",LAPACKtrsen_("N","V",selection,&n,T,&ld,Q,&ld,wr,wi,&mout,&dummy,&dummy,work,&lwork,iwork,&liwork,&info));
     293             : #else
     294             :   PetscCallBLAS("LAPACKtrsen",LAPACKtrsen_("N","V",selection,&n,T,&ld,Q,&ld,wr,&mout,&dummy,&dummy,work,&lwork,&info));
     295             : #endif
     296          17 :   SlepcCheckLapackInfo("trsen",info);
     297          17 :   *k = mout;
     298          17 :   PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_A],&T));
     299          17 :   PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_Q],&Q));
     300          17 :   PetscFunctionReturn(PETSC_SUCCESS);
     301             : }
     302             : 
     303        3815 : static PetscErrorCode DSSort_NHEP(DS ds,PetscScalar *wr,PetscScalar *wi,PetscScalar *rr,PetscScalar *ri,PetscInt *k)
     304             : {
     305        3815 :   PetscFunctionBegin;
     306        3815 :   if (!rr || wr == rr) PetscCall(DSSort_NHEP_Total(ds,DS_MAT_A,DS_MAT_Q,wr,wi));
     307          17 :   else PetscCall(DSSort_NHEP_Arbitrary(ds,wr,wi,rr,ri,k));
     308        3815 :   PetscFunctionReturn(PETSC_SUCCESS);
     309             : }
     310             : 
     311           1 : static PetscErrorCode DSSortWithPermutation_NHEP(DS ds,PetscInt *perm,PetscScalar *wr,PetscScalar *wi)
     312             : {
     313           1 :   PetscFunctionBegin;
     314           1 :   PetscCall(DSSortWithPermutation_NHEP_Private(ds,perm,DS_MAT_A,DS_MAT_Q,wr,wi));
     315           1 :   PetscFunctionReturn(PETSC_SUCCESS);
     316             : }
     317             : 
     318        2799 : static PetscErrorCode DSUpdateExtraRow_NHEP(DS ds)
     319             : {
     320        2799 :   PetscInt          i;
     321        2799 :   PetscBLASInt      n,ld,incx=1;
     322        2799 :   PetscScalar       *A,*x,*y,one=1.0,zero=0.0;
     323        2799 :   const PetscScalar *Q;
     324             : 
     325        2799 :   PetscFunctionBegin;
     326        2799 :   PetscCall(PetscBLASIntCast(ds->n,&n));
     327        2799 :   PetscCall(PetscBLASIntCast(ds->ld,&ld));
     328        2799 :   PetscCall(MatDenseGetArray(ds->omat[DS_MAT_A],&A));
     329        2799 :   PetscCall(MatDenseGetArrayRead(ds->omat[DS_MAT_Q],&Q));
     330        2799 :   PetscCall(DSAllocateWork_Private(ds,2*ld,0,0));
     331        2799 :   x = ds->work;
     332        2799 :   y = ds->work+ld;
     333       56158 :   for (i=0;i<n;i++) x[i] = PetscConj(A[n+i*ld]);
     334        2799 :   PetscCallBLAS("BLASgemv",BLASgemv_("C",&n,&n,&one,Q,&ld,x,&incx,&zero,y,&incx));
     335       56158 :   for (i=0;i<n;i++) A[n+i*ld] = PetscConj(y[i]);
     336        2799 :   PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_A],&A));
     337        2799 :   PetscCall(MatDenseRestoreArrayRead(ds->omat[DS_MAT_Q],&Q));
     338        2799 :   ds->k = n;
     339        2799 :   PetscFunctionReturn(PETSC_SUCCESS);
     340             : }
     341             : 
     342        3416 : static PetscErrorCode DSSolve_NHEP(DS ds,PetscScalar *wr,PetscScalar *wi)
     343             : {
     344        3416 :   PetscFunctionBegin;
     345             : #if !defined(PETSC_USE_COMPLEX)
     346        3416 :   PetscAssertPointer(wi,3);
     347             : #endif
     348        3416 :   PetscCall(DSSolve_NHEP_Private(ds,DS_MAT_A,DS_MAT_Q,wr,wi));
     349        3416 :   PetscFunctionReturn(PETSC_SUCCESS);
     350             : }
     351             : 
     352             : #if !defined(PETSC_HAVE_MPIUNI)
     353          31 : static PetscErrorCode DSSynchronize_NHEP(DS ds,PetscScalar eigr[],PetscScalar eigi[])
     354             : {
     355          31 :   PetscInt       ld=ds->ld,l=ds->l,k;
     356          31 :   PetscMPIInt    n,rank,off=0,size,ldn;
     357          31 :   PetscScalar    *A,*Q;
     358             : 
     359          31 :   PetscFunctionBegin;
     360          31 :   k = (ds->n-l)*ld;
     361          31 :   if (ds->state>DS_STATE_RAW) k += (ds->n-l)*ld;
     362          31 :   if (eigr) k += ds->n-l;
     363          31 :   if (eigi) k += ds->n-l;
     364          31 :   PetscCall(DSAllocateWork_Private(ds,k,0,0));
     365          31 :   PetscCall(PetscMPIIntCast(k*sizeof(PetscScalar),&size));
     366          31 :   PetscCall(PetscMPIIntCast(ds->n-l,&n));
     367          31 :   PetscCall(PetscMPIIntCast(ld*(ds->n-l),&ldn));
     368          31 :   PetscCall(MatDenseGetArray(ds->omat[DS_MAT_A],&A));
     369          31 :   if (ds->state>DS_STATE_RAW) PetscCall(MatDenseGetArray(ds->omat[DS_MAT_Q],&Q));
     370          31 :   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)ds),&rank));
     371          31 :   if (!rank) {
     372          15 :     PetscCallMPI(MPI_Pack(A+l*ld,ldn,MPIU_SCALAR,ds->work,size,&off,PetscObjectComm((PetscObject)ds)));
     373          15 :     if (ds->state>DS_STATE_RAW) PetscCallMPI(MPI_Pack(Q+l*ld,ldn,MPIU_SCALAR,ds->work,size,&off,PetscObjectComm((PetscObject)ds)));
     374          15 :     if (eigr) PetscCallMPI(MPI_Pack(eigr+l,n,MPIU_SCALAR,ds->work,size,&off,PetscObjectComm((PetscObject)ds)));
     375             : #if !defined(PETSC_USE_COMPLEX)
     376          15 :     if (eigi) PetscCallMPI(MPI_Pack(eigi+l,n,MPIU_SCALAR,ds->work,size,&off,PetscObjectComm((PetscObject)ds)));
     377             : #endif
     378             :   }
     379          62 :   PetscCallMPI(MPI_Bcast(ds->work,size,MPI_BYTE,0,PetscObjectComm((PetscObject)ds)));
     380          31 :   if (rank) {
     381          16 :     PetscCallMPI(MPI_Unpack(ds->work,size,&off,A+l*ld,ldn,MPIU_SCALAR,PetscObjectComm((PetscObject)ds)));
     382          16 :     if (ds->state>DS_STATE_RAW) PetscCallMPI(MPI_Unpack(ds->work,size,&off,Q+l*ld,ldn,MPIU_SCALAR,PetscObjectComm((PetscObject)ds)));
     383          16 :     if (eigr) PetscCallMPI(MPI_Unpack(ds->work,size,&off,eigr+l,n,MPIU_SCALAR,PetscObjectComm((PetscObject)ds)));
     384             : #if !defined(PETSC_USE_COMPLEX)
     385          16 :     if (eigi) PetscCallMPI(MPI_Unpack(ds->work,size,&off,eigi+l,n,MPIU_SCALAR,PetscObjectComm((PetscObject)ds)));
     386             : #endif
     387             :   }
     388          31 :   PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_A],&A));
     389          31 :   if (ds->state>DS_STATE_RAW) PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_Q],&Q));
     390          31 :   PetscFunctionReturn(PETSC_SUCCESS);
     391             : }
     392             : #endif
     393             : 
     394        1938 : static PetscErrorCode DSTruncate_NHEP(DS ds,PetscInt n,PetscBool trim)
     395             : {
     396        1938 :   PetscInt    i,ld=ds->ld,l=ds->l;
     397        1938 :   PetscScalar *A;
     398             : 
     399        1938 :   PetscFunctionBegin;
     400        1938 :   PetscCall(MatDenseGetArray(ds->omat[DS_MAT_A],&A));
     401             : #if defined(PETSC_USE_DEBUG)
     402             :   /* make sure diagonal 2x2 block is not broken */
     403        1938 :   PetscCheck(ds->state<DS_STATE_CONDENSED || n==0 || n==ds->n || A[n+(n-1)*ld]==0.0,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"The given size would break a 2x2 block, call DSGetTruncateSize() first");
     404             : #endif
     405        1938 :   if (trim) {
     406         307 :     if (ds->extrarow) {   /* clean extra row */
     407        5716 :       for (i=l;i<ds->n;i++) A[ds->n+i*ld] = 0.0;
     408             :     }
     409         307 :     ds->l = 0;
     410         307 :     ds->k = 0;
     411         307 :     ds->n = n;
     412         307 :     ds->t = ds->n;   /* truncated length equal to the new dimension */
     413             :   } else {
     414        1631 :     if (ds->extrarow && ds->k==ds->n) {
     415             :       /* copy entries of extra row to the new position, then clean last row */
     416       17430 :       for (i=l;i<n;i++) A[n+i*ld] = A[ds->n+i*ld];
     417       33012 :       for (i=l;i<ds->n;i++) A[ds->n+i*ld] = 0.0;
     418             :     }
     419        1631 :     ds->k = (ds->extrarow)? n: 0;
     420        1631 :     ds->t = ds->n;   /* truncated length equal to previous dimension */
     421        1631 :     ds->n = n;
     422             :   }
     423        1938 :   PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_A],&A));
     424        1938 :   PetscFunctionReturn(PETSC_SUCCESS);
     425             : }
     426             : 
     427          41 : static PetscErrorCode DSCond_NHEP(DS ds,PetscReal *cond)
     428             : {
     429          41 :   PetscScalar    *work;
     430          41 :   PetscReal      *rwork;
     431          41 :   PetscBLASInt   *ipiv;
     432          41 :   PetscBLASInt   lwork,info,n,ld;
     433          41 :   PetscReal      hn,hin;
     434          41 :   PetscScalar    *A;
     435             : 
     436          41 :   PetscFunctionBegin;
     437          41 :   PetscCall(PetscBLASIntCast(ds->n,&n));
     438          41 :   PetscCall(PetscBLASIntCast(ds->ld,&ld));
     439          41 :   lwork = 8*ld;
     440          41 :   PetscCall(DSAllocateWork_Private(ds,lwork,ld,ld));
     441          41 :   work  = ds->work;
     442          41 :   rwork = ds->rwork;
     443          41 :   ipiv  = ds->iwork;
     444             : 
     445             :   /* use workspace matrix W to avoid overwriting A */
     446          41 :   PetscCall(DSAllocateMat_Private(ds,DS_MAT_W));
     447          41 :   PetscCall(MatCopy(ds->omat[DS_MAT_A],ds->omat[DS_MAT_W],SAME_NONZERO_PATTERN));
     448          41 :   PetscCall(MatDenseGetArray(ds->omat[DS_MAT_W],&A));
     449             : 
     450             :   /* norm of A */
     451          41 :   if (ds->state<DS_STATE_INTERMEDIATE) hn = LAPACKlange_("I",&n,&n,A,&ld,rwork);
     452          41 :   else hn = LAPACKlanhs_("I",&n,A,&ld,rwork);
     453             : 
     454             :   /* norm of inv(A) */
     455          41 :   PetscCallBLAS("LAPACKgetrf",LAPACKgetrf_(&n,&n,A,&ld,ipiv,&info));
     456          41 :   SlepcCheckLapackInfo("getrf",info);
     457          41 :   PetscCallBLAS("LAPACKgetri",LAPACKgetri_(&n,A,&ld,ipiv,work,&lwork,&info));
     458          41 :   SlepcCheckLapackInfo("getri",info);
     459          41 :   hin = LAPACKlange_("I",&n,&n,A,&ld,rwork);
     460          41 :   PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_W],&A));
     461             : 
     462          41 :   *cond = hn*hin;
     463          41 :   PetscFunctionReturn(PETSC_SUCCESS);
     464             : }
     465             : 
     466          81 : static PetscErrorCode DSTranslateHarmonic_NHEP(DS ds,PetscScalar tau,PetscReal beta,PetscBool recover,PetscScalar *gin,PetscReal *gammaout)
     467             : {
     468          81 :   PetscInt          i,j;
     469          81 :   PetscBLASInt      *ipiv,info,n,ld,one=1,ncol;
     470          81 :   PetscScalar       *A,*B,*g=gin,*ghat,done=1.0,dmone=-1.0,dzero=0.0;
     471          81 :   const PetscScalar *Q;
     472          81 :   PetscReal         gamma=1.0;
     473             : 
     474          81 :   PetscFunctionBegin;
     475          81 :   PetscCall(PetscBLASIntCast(ds->n,&n));
     476          81 :   PetscCall(PetscBLASIntCast(ds->ld,&ld));
     477          81 :   PetscCall(MatDenseGetArray(ds->omat[DS_MAT_A],&A));
     478             : 
     479          81 :   if (!recover) {
     480             : 
     481          57 :     PetscCall(DSAllocateWork_Private(ds,0,0,ld));
     482          57 :     ipiv = ds->iwork;
     483          57 :     if (!g) {
     484          28 :       PetscCall(DSAllocateWork_Private(ds,ld,0,0));
     485          28 :       g = ds->work;
     486             :     }
     487             :     /* use workspace matrix W to factor A-tau*eye(n) */
     488          57 :     PetscCall(DSAllocateMat_Private(ds,DS_MAT_W));
     489          57 :     PetscCall(MatCopy(ds->omat[DS_MAT_A],ds->omat[DS_MAT_W],SAME_NONZERO_PATTERN));
     490          57 :     PetscCall(MatDenseGetArray(ds->omat[DS_MAT_W],&B));
     491             : 
     492             :     /* Vector g initially stores b = beta*e_n^T */
     493          57 :     PetscCall(PetscArrayzero(g,n));
     494          57 :     g[n-1] = beta;
     495             : 
     496             :     /* g = (A-tau*eye(n))'\b */
     497        1125 :     for (i=0;i<n;i++) B[i+i*ld] -= tau;
     498          57 :     PetscCallBLAS("LAPACKgetrf",LAPACKgetrf_(&n,&n,B,&ld,ipiv,&info));
     499          57 :     SlepcCheckLapackInfo("getrf",info);
     500          57 :     PetscCall(PetscLogFlops(2.0*n*n*n/3.0));
     501          57 :     PetscCallBLAS("LAPACKgetrs",LAPACKgetrs_("C",&n,&one,B,&ld,ipiv,g,&ld,&info));
     502          57 :     SlepcCheckLapackInfo("getrs",info);
     503          57 :     PetscCall(PetscLogFlops(2.0*n*n-n));
     504          57 :     PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_W],&B));
     505             : 
     506             :     /* A = A + g*b' */
     507        1125 :     for (i=0;i<n;i++) A[i+(n-1)*ld] += g[i]*beta;
     508             : 
     509             :   } else { /* recover */
     510             : 
     511          24 :     PetscCall(DSAllocateWork_Private(ds,ld,0,0));
     512          24 :     ghat = ds->work;
     513          24 :     PetscCall(MatDenseGetArrayRead(ds->omat[DS_MAT_Q],&Q));
     514             : 
     515             :     /* g^ = -Q(:,idx)'*g */
     516          24 :     PetscCall(PetscBLASIntCast(ds->l+ds->k,&ncol));
     517          24 :     PetscCallBLAS("BLASgemv",BLASgemv_("C",&n,&ncol,&dmone,Q,&ld,g,&one,&dzero,ghat,&one));
     518             : 
     519             :     /* A = A + g^*b' */
     520         238 :     for (i=0;i<ds->l+ds->k;i++)
     521        2112 :       for (j=ds->l;j<ds->l+ds->k;j++)
     522        1898 :         A[i+j*ld] += ghat[i]*Q[n-1+j*ld]*beta;
     523             : 
     524             :     /* g~ = (I-Q(:,idx)*Q(:,idx)')*g = g+Q(:,idx)*g^ */
     525          24 :     PetscCallBLAS("BLASgemv",BLASgemv_("N",&n,&ncol,&done,Q,&ld,ghat,&one,&done,g,&one));
     526          24 :     PetscCall(MatDenseRestoreArrayRead(ds->omat[DS_MAT_Q],&Q));
     527             :   }
     528             : 
     529             :   /* Compute gamma factor */
     530          81 :   if (gammaout || (recover && ds->extrarow)) gamma = SlepcAbs(1.0,BLASnrm2_(&n,g,&one));
     531          81 :   if (gammaout) *gammaout = gamma;
     532          81 :   if (recover && ds->extrarow) {
     533         236 :     for (j=ds->l;j<ds->l+ds->k;j++) A[ds->n+j*ld] *= gamma;
     534             :   }
     535          81 :   PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_A],&A));
     536          81 :   PetscFunctionReturn(PETSC_SUCCESS);
     537             : }
     538             : 
     539             : /*MC
     540             :    DSNHEP - Dense Non-Hermitian Eigenvalue Problem.
     541             : 
     542             :    Level: beginner
     543             : 
     544             :    Notes:
     545             :    The problem is expressed as A*X = X*Lambda, where A is the input matrix.
     546             :    Lambda is a diagonal matrix whose diagonal elements are the arguments of
     547             :    DSSolve(). After solve, A is overwritten with the upper quasi-triangular
     548             :    matrix T of the (real) Schur form, A*Q = Q*T.
     549             : 
     550             :    In the intermediate state A is reduced to upper Hessenberg form.
     551             : 
     552             :    Computation of left eigenvectors is supported, but two-sided Krylov solvers
     553             :    usually rely on the related DSNHEPTS.
     554             : 
     555             :    Used DS matrices:
     556             : +  DS_MAT_A - problem matrix
     557             : -  DS_MAT_Q - orthogonal/unitary transformation that reduces to Hessenberg form
     558             :    (intermediate step) or matrix of orthogonal Schur vectors
     559             : 
     560             :    Implemented methods:
     561             : .  0 - Implicit QR (_hseqr)
     562             : 
     563             : .seealso: DSCreate(), DSSetType(), DSType
     564             : M*/
     565         876 : SLEPC_EXTERN PetscErrorCode DSCreate_NHEP(DS ds)
     566             : {
     567         876 :   PetscFunctionBegin;
     568         876 :   ds->ops->allocate        = DSAllocate_NHEP;
     569         876 :   ds->ops->view            = DSView_NHEP;
     570         876 :   ds->ops->vectors         = DSVectors_NHEP;
     571         876 :   ds->ops->solve[0]        = DSSolve_NHEP;
     572         876 :   ds->ops->sort            = DSSort_NHEP;
     573         876 :   ds->ops->sortperm        = DSSortWithPermutation_NHEP;
     574             : #if !defined(PETSC_HAVE_MPIUNI)
     575         876 :   ds->ops->synchronize     = DSSynchronize_NHEP;
     576             : #endif
     577         876 :   ds->ops->gettruncatesize = DSGetTruncateSize_Default;
     578         876 :   ds->ops->truncate        = DSTruncate_NHEP;
     579         876 :   ds->ops->update          = DSUpdateExtraRow_NHEP;
     580         876 :   ds->ops->cond            = DSCond_NHEP;
     581         876 :   ds->ops->transharm       = DSTranslateHarmonic_NHEP;
     582         876 :   PetscFunctionReturn(PETSC_SUCCESS);
     583             : }

Generated by: LCOV version 1.14