Mercurial > octave-nkf
diff libcruft/arpack/src/dneupd.f @ 12274:9f5d2ef078e8 release-3-4-x
import ARPACK sources to libcruft from Debian package libarpack2 2.1+parpack96.dfsg-3+b1
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Fri, 28 Jan 2011 14:04:33 -0500 |
parents | |
children | 9ed4018d538c |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcruft/arpack/src/dneupd.f Fri Jan 28 14:04:33 2011 -0500 @@ -0,0 +1,1063 @@ +c\BeginDoc +c +c\Name: dneupd +c +c\Description: +c +c This subroutine returns the converged approximations to eigenvalues +c of A*z = lambda*B*z and (optionally): +c +c (1) The corresponding approximate eigenvectors; +c +c (2) An orthonormal basis for the associated approximate +c invariant subspace; +c +c (3) Both. +c +c There is negligible additional cost to obtain eigenvectors. An orthonormal +c basis is always computed. There is an additional storage cost of n*nev +c if both are requested (in this case a separate array Z must be supplied). +c +c The approximate eigenvalues and eigenvectors of A*z = lambda*B*z +c are derived from approximate eigenvalues and eigenvectors of +c of the linear operator OP prescribed by the MODE selection in the +c call to DNAUPD . DNAUPD must be called before this routine is called. +c These approximate eigenvalues and vectors are commonly called Ritz +c values and Ritz vectors respectively. They are referred to as such +c in the comments that follow. The computed orthonormal basis for the +c invariant subspace corresponding to these Ritz values is referred to as a +c Schur basis. +c +c See documentation in the header of the subroutine DNAUPD for +c definition of OP as well as other terms and the relation of computed +c Ritz values and Ritz vectors of OP with respect to the given problem +c A*z = lambda*B*z. For a brief description, see definitions of +c IPARAM(7), MODE and WHICH in the documentation of DNAUPD . +c +c\Usage: +c call dneupd +c ( RVEC, HOWMNY, SELECT, DR, DI, Z, LDZ, SIGMAR, SIGMAI, WORKEV, BMAT, +c N, WHICH, NEV, TOL, RESID, NCV, V, LDV, IPARAM, IPNTR, WORKD, WORKL, +c LWORKL, INFO ) +c +c\Arguments: +c RVEC LOGICAL (INPUT) +c Specifies whether a basis for the invariant subspace corresponding +c to the converged Ritz value approximations for the eigenproblem +c A*z = lambda*B*z is computed. +c +c RVEC = .FALSE. Compute Ritz values only. +c +c RVEC = .TRUE. Compute the Ritz vectors or Schur vectors. +c See Remarks below. +c +c HOWMNY Character*1 (INPUT) +c Specifies the form of the basis for the invariant subspace +c corresponding to the converged Ritz values that is to be computed. +c +c = 'A': Compute NEV Ritz vectors; +c = 'P': Compute NEV Schur vectors; +c = 'S': compute some of the Ritz vectors, specified +c by the logical array SELECT. +c +c SELECT Logical array of dimension NCV. (INPUT) +c If HOWMNY = 'S', SELECT specifies the Ritz vectors to be +c computed. To select the Ritz vector corresponding to a +c Ritz value (DR(j), DI(j)), SELECT(j) must be set to .TRUE.. +c If HOWMNY = 'A' or 'P', SELECT is used as internal workspace. +c +c DR Double precision array of dimension NEV+1. (OUTPUT) +c If IPARAM(7) = 1,2 or 3 and SIGMAI=0.0 then on exit: DR contains +c the real part of the Ritz approximations to the eigenvalues of +c A*z = lambda*B*z. +c If IPARAM(7) = 3, 4 and SIGMAI is not equal to zero, then on exit: +c DR contains the real part of the Ritz values of OP computed by +c DNAUPD . A further computation must be performed by the user +c to transform the Ritz values computed for OP by DNAUPD to those +c of the original system A*z = lambda*B*z. See remark 3 below. +c +c DI Double precision array of dimension NEV+1. (OUTPUT) +c On exit, DI contains the imaginary part of the Ritz value +c approximations to the eigenvalues of A*z = lambda*B*z associated +c with DR. +c +c NOTE: When Ritz values are complex, they will come in complex +c conjugate pairs. If eigenvectors are requested, the +c corresponding Ritz vectors will also come in conjugate +c pairs and the real and imaginary parts of these are +c represented in two consecutive columns of the array Z +c (see below). +c +c Z Double precision N by NEV+1 array if RVEC = .TRUE. and HOWMNY = 'A'. (OUTPUT) +c On exit, if RVEC = .TRUE. and HOWMNY = 'A', then the columns of +c Z represent approximate eigenvectors (Ritz vectors) corresponding +c to the NCONV=IPARAM(5) Ritz values for eigensystem +c A*z = lambda*B*z. +c +c The complex Ritz vector associated with the Ritz value +c with positive imaginary part is stored in two consecutive +c columns. The first column holds the real part of the Ritz +c vector and the second column holds the imaginary part. The +c Ritz vector associated with the Ritz value with negative +c imaginary part is simply the complex conjugate of the Ritz vector +c associated with the positive imaginary part. +c +c If RVEC = .FALSE. or HOWMNY = 'P', then Z is not referenced. +c +c NOTE: If if RVEC = .TRUE. and a Schur basis is not required, +c the array Z may be set equal to first NEV+1 columns of the Arnoldi +c basis array V computed by DNAUPD . In this case the Arnoldi basis +c will be destroyed and overwritten with the eigenvector basis. +c +c LDZ Integer. (INPUT) +c The leading dimension of the array Z. If Ritz vectors are +c desired, then LDZ >= max( 1, N ). In any case, LDZ >= 1. +c +c SIGMAR Double precision (INPUT) +c If IPARAM(7) = 3 or 4, represents the real part of the shift. +c Not referenced if IPARAM(7) = 1 or 2. +c +c SIGMAI Double precision (INPUT) +c If IPARAM(7) = 3 or 4, represents the imaginary part of the shift. +c Not referenced if IPARAM(7) = 1 or 2. See remark 3 below. +c +c WORKEV Double precision work array of dimension 3*NCV. (WORKSPACE) +c +c **** The remaining arguments MUST be the same as for the **** +c **** call to DNAUPD that was just completed. **** +c +c NOTE: The remaining arguments +c +c BMAT, N, WHICH, NEV, TOL, RESID, NCV, V, LDV, IPARAM, IPNTR, +c WORKD, WORKL, LWORKL, INFO +c +c must be passed directly to DNEUPD following the last call +c to DNAUPD . These arguments MUST NOT BE MODIFIED between +c the the last call to DNAUPD and the call to DNEUPD . +c +c Three of these parameters (V, WORKL, INFO) are also output parameters: +c +c V Double precision N by NCV array. (INPUT/OUTPUT) +c +c Upon INPUT: the NCV columns of V contain the Arnoldi basis +c vectors for OP as constructed by DNAUPD . +c +c Upon OUTPUT: If RVEC = .TRUE. the first NCONV=IPARAM(5) columns +c contain approximate Schur vectors that span the +c desired invariant subspace. See Remark 2 below. +c +c NOTE: If the array Z has been set equal to first NEV+1 columns +c of the array V and RVEC=.TRUE. and HOWMNY= 'A', then the +c Arnoldi basis held by V has been overwritten by the desired +c Ritz vectors. If a separate array Z has been passed then +c the first NCONV=IPARAM(5) columns of V will contain approximate +c Schur vectors that span the desired invariant subspace. +c +c WORKL Double precision work array of length LWORKL. (OUTPUT/WORKSPACE) +c WORKL(1:ncv*ncv+3*ncv) contains information obtained in +c dnaupd . They are not changed by dneupd . +c WORKL(ncv*ncv+3*ncv+1:3*ncv*ncv+6*ncv) holds the +c real and imaginary part of the untransformed Ritz values, +c the upper quasi-triangular matrix for H, and the +c associated matrix representation of the invariant subspace for H. +c +c Note: IPNTR(9:13) contains the pointer into WORKL for addresses +c of the above information computed by dneupd . +c ------------------------------------------------------------- +c IPNTR(9): pointer to the real part of the NCV RITZ values of the +c original system. +c IPNTR(10): pointer to the imaginary part of the NCV RITZ values of +c the original system. +c IPNTR(11): pointer to the NCV corresponding error bounds. +c IPNTR(12): pointer to the NCV by NCV upper quasi-triangular +c Schur matrix for H. +c IPNTR(13): pointer to the NCV by NCV matrix of eigenvectors +c of the upper Hessenberg matrix H. Only referenced by +c dneupd if RVEC = .TRUE. See Remark 2 below. +c ------------------------------------------------------------- +c +c INFO Integer. (OUTPUT) +c Error flag on output. +c +c = 0: Normal exit. +c +c = 1: The Schur form computed by LAPACK routine dlahqr +c could not be reordered by LAPACK routine dtrsen . +c Re-enter subroutine dneupd with IPARAM(5)=NCV and +c increase the size of the arrays DR and DI to have +c dimension at least dimension NCV and allocate at least NCV +c columns for Z. NOTE: Not necessary if Z and V share +c the same space. Please notify the authors if this error +c occurs. +c +c = -1: N must be positive. +c = -2: NEV must be positive. +c = -3: NCV-NEV >= 2 and less than or equal to N. +c = -5: WHICH must be one of 'LM', 'SM', 'LR', 'SR', 'LI', 'SI' +c = -6: BMAT must be one of 'I' or 'G'. +c = -7: Length of private work WORKL array is not sufficient. +c = -8: Error return from calculation of a real Schur form. +c Informational error from LAPACK routine dlahqr . +c = -9: Error return from calculation of eigenvectors. +c Informational error from LAPACK routine dtrevc . +c = -10: IPARAM(7) must be 1,2,3,4. +c = -11: IPARAM(7) = 1 and BMAT = 'G' are incompatible. +c = -12: HOWMNY = 'S' not yet implemented +c = -13: HOWMNY must be one of 'A' or 'P' if RVEC = .true. +c = -14: DNAUPD did not find any eigenvalues to sufficient +c accuracy. +c = -15: DNEUPD got a different count of the number of converged +c Ritz values than DNAUPD got. This indicates the user +c probably made an error in passing data from DNAUPD to +c DNEUPD or that the data was modified before entering +c DNEUPD +c +c\BeginLib +c +c\References: +c 1. D.C. Sorensen, "Implicit Application of Polynomial Filters in +c a k-Step Arnoldi Method", SIAM J. Matr. Anal. Apps., 13 (1992), +c pp 357-385. +c 2. R.B. Lehoucq, "Analysis and Implementation of an Implicitly +c Restarted Arnoldi Iteration", Rice University Technical Report +c TR95-13, Department of Computational and Applied Mathematics. +c 3. B.N. Parlett & Y. Saad, "Complex Shift and Invert Strategies for +c Real Matrices", Linear Algebra and its Applications, vol 88/89, +c pp 575-595, (1987). +c +c\Routines called: +c ivout ARPACK utility routine that prints integers. +c dmout ARPACK utility routine that prints matrices +c dvout ARPACK utility routine that prints vectors. +c dgeqr2 LAPACK routine that computes the QR factorization of +c a matrix. +c dlacpy LAPACK matrix copy routine. +c dlahqr LAPACK routine to compute the real Schur form of an +c upper Hessenberg matrix. +c dlamch LAPACK routine that determines machine constants. +c dlapy2 LAPACK routine to compute sqrt(x**2+y**2) carefully. +c dlaset LAPACK matrix initialization routine. +c dorm2r LAPACK routine that applies an orthogonal matrix in +c factored form. +c dtrevc LAPACK routine to compute the eigenvectors of a matrix +c in upper quasi-triangular form. +c dtrsen LAPACK routine that re-orders the Schur form. +c dtrmm Level 3 BLAS matrix times an upper triangular matrix. +c dger Level 2 BLAS rank one update to a matrix. +c dcopy Level 1 BLAS that copies one vector to another . +c ddot Level 1 BLAS that computes the scalar product of two vectors. +c dnrm2 Level 1 BLAS that computes the norm of a vector. +c dscal Level 1 BLAS that scales a vector. +c +c\Remarks +c +c 1. Currently only HOWMNY = 'A' and 'P' are implemented. +c +c Let trans(X) denote the transpose of X. +c +c 2. Schur vectors are an orthogonal representation for the basis of +c Ritz vectors. Thus, their numerical properties are often superior. +c If RVEC = .TRUE. then the relationship +c A * V(:,1:IPARAM(5)) = V(:,1:IPARAM(5)) * T, and +c trans(V(:,1:IPARAM(5))) * V(:,1:IPARAM(5)) = I are approximately +c satisfied. Here T is the leading submatrix of order IPARAM(5) of the +c real upper quasi-triangular matrix stored workl(ipntr(12)). That is, +c T is block upper triangular with 1-by-1 and 2-by-2 diagonal blocks; +c each 2-by-2 diagonal block has its diagonal elements equal and its +c off-diagonal elements of opposite sign. Corresponding to each 2-by-2 +c diagonal block is a complex conjugate pair of Ritz values. The real +c Ritz values are stored on the diagonal of T. +c +c 3. If IPARAM(7) = 3 or 4 and SIGMAI is not equal zero, then the user must +c form the IPARAM(5) Rayleigh quotients in order to transform the Ritz +c values computed by DNAUPD for OP to those of A*z = lambda*B*z. +c Set RVEC = .true. and HOWMNY = 'A', and +c compute +c trans(Z(:,I)) * A * Z(:,I) if DI(I) = 0. +c If DI(I) is not equal to zero and DI(I+1) = - D(I), +c then the desired real and imaginary parts of the Ritz value are +c trans(Z(:,I)) * A * Z(:,I) + trans(Z(:,I+1)) * A * Z(:,I+1), +c trans(Z(:,I)) * A * Z(:,I+1) - trans(Z(:,I+1)) * A * Z(:,I), +c respectively. +c Another possibility is to set RVEC = .true. and HOWMNY = 'P' and +c compute trans(V(:,1:IPARAM(5))) * A * V(:,1:IPARAM(5)) and then an upper +c quasi-triangular matrix of order IPARAM(5) is computed. See remark +c 2 above. +c +c\Authors +c Danny Sorensen Phuong Vu +c Richard Lehoucq CRPC / Rice University +c Chao Yang Houston, Texas +c Dept. of Computational & +c Applied Mathematics +c Rice University +c Houston, Texas +c +c\SCCS Information: @(#) +c FILE: neupd.F SID: 2.7 DATE OF SID: 09/20/00 RELEASE: 2 +c +c\EndLib +c +c----------------------------------------------------------------------- + subroutine dneupd (rvec , howmny, select, dr , di, + & z , ldz , sigmar, sigmai, workev, + & bmat , n , which , nev , tol, + & resid, ncv , v , ldv , iparam, + & ipntr, workd , workl , lworkl, info) +c +c %----------------------------------------------------% +c | Include files for debugging and timing information | +c %----------------------------------------------------% +c + include 'debug.h' + include 'stat.h' +c +c %------------------% +c | Scalar Arguments | +c %------------------% +c + character bmat, howmny, which*2 + logical rvec + integer info, ldz, ldv, lworkl, n, ncv, nev + Double precision + & sigmar, sigmai, tol +c +c %-----------------% +c | Array Arguments | +c %-----------------% +c + integer iparam(11), ipntr(14) + logical select(ncv) + Double precision + & dr(nev+1) , di(nev+1), resid(n) , + & v(ldv,ncv) , z(ldz,*) , workd(3*n), + & workl(lworkl), workev(3*ncv) +c +c %------------% +c | Parameters | +c %------------% +c + Double precision + & one, zero + parameter (one = 1.0D+0 , zero = 0.0D+0 ) +c +c %---------------% +c | Local Scalars | +c %---------------% +c + character type*6 + integer bounds, ierr , ih , ihbds , + & iheigr, iheigi, iconj , nconv , + & invsub, iuptri, iwev , iwork(1), + & j , k , ldh , ldq , + & mode , msglvl, outncv, ritzr , + & ritzi , wri , wrr , irr , + & iri , ibd , ishift, numcnv , + & np , jj + logical reord + Double precision + & conds , rnorm, sep , temp, + & vl(1,1), temp1, eps23 +c +c %----------------------% +c | External Subroutines | +c %----------------------% +c + external dcopy , dger , dgeqr2 , dlacpy , + & dlahqr , dlaset , dmout , dorm2r , + & dtrevc , dtrmm , dtrsen , dscal , + & dvout , ivout +c +c %--------------------% +c | External Functions | +c %--------------------% +c + Double precision + & dlapy2 , dnrm2 , dlamch , ddot + external dlapy2 , dnrm2 , dlamch , ddot +c +c %---------------------% +c | Intrinsic Functions | +c %---------------------% +c + intrinsic abs, min, sqrt +c +c %-----------------------% +c | Executable Statements | +c %-----------------------% +c +c %------------------------% +c | Set default parameters | +c %------------------------% +c + msglvl = mneupd + mode = iparam(7) + nconv = iparam(5) + info = 0 +c +c %---------------------------------% +c | Get machine dependent constant. | +c %---------------------------------% +c + eps23 = dlamch ('Epsilon-Machine') + eps23 = eps23**(2.0D+0 / 3.0D+0 ) +c +c %--------------% +c | Quick return | +c %--------------% +c + ierr = 0 +c + if (nconv .le. 0) then + ierr = -14 + else if (n .le. 0) then + ierr = -1 + else if (nev .le. 0) then + ierr = -2 + else if (ncv .le. nev+1 .or. ncv .gt. n) then + ierr = -3 + else if (which .ne. 'LM' .and. + & which .ne. 'SM' .and. + & which .ne. 'LR' .and. + & which .ne. 'SR' .and. + & which .ne. 'LI' .and. + & which .ne. 'SI') then + ierr = -5 + else if (bmat .ne. 'I' .and. bmat .ne. 'G') then + ierr = -6 + else if (lworkl .lt. 3*ncv**2 + 6*ncv) then + ierr = -7 + else if ( (howmny .ne. 'A' .and. + & howmny .ne. 'P' .and. + & howmny .ne. 'S') .and. rvec ) then + ierr = -13 + else if (howmny .eq. 'S' ) then + ierr = -12 + end if +c + if (mode .eq. 1 .or. mode .eq. 2) then + type = 'REGULR' + else if (mode .eq. 3 .and. sigmai .eq. zero) then + type = 'SHIFTI' + else if (mode .eq. 3 ) then + type = 'REALPT' + else if (mode .eq. 4 ) then + type = 'IMAGPT' + else + ierr = -10 + end if + if (mode .eq. 1 .and. bmat .eq. 'G') ierr = -11 +c +c %------------% +c | Error Exit | +c %------------% +c + if (ierr .ne. 0) then + info = ierr + go to 9000 + end if +c +c %--------------------------------------------------------% +c | Pointer into WORKL for address of H, RITZ, BOUNDS, Q | +c | etc... and the remaining workspace. | +c | Also update pointer to be used on output. | +c | Memory is laid out as follows: | +c | workl(1:ncv*ncv) := generated Hessenberg matrix | +c | workl(ncv*ncv+1:ncv*ncv+2*ncv) := real and imaginary | +c | parts of ritz values | +c | workl(ncv*ncv+2*ncv+1:ncv*ncv+3*ncv) := error bounds | +c %--------------------------------------------------------% +c +c %-----------------------------------------------------------% +c | The following is used and set by DNEUPD . | +c | workl(ncv*ncv+3*ncv+1:ncv*ncv+4*ncv) := The untransformed | +c | real part of the Ritz values. | +c | workl(ncv*ncv+4*ncv+1:ncv*ncv+5*ncv) := The untransformed | +c | imaginary part of the Ritz values. | +c | workl(ncv*ncv+5*ncv+1:ncv*ncv+6*ncv) := The untransformed | +c | error bounds of the Ritz values | +c | workl(ncv*ncv+6*ncv+1:2*ncv*ncv+6*ncv) := Holds the upper | +c | quasi-triangular matrix for H | +c | workl(2*ncv*ncv+6*ncv+1: 3*ncv*ncv+6*ncv) := Holds the | +c | associated matrix representation of the invariant | +c | subspace for H. | +c | GRAND total of NCV * ( 3 * NCV + 6 ) locations. | +c %-----------------------------------------------------------% +c + ih = ipntr(5) + ritzr = ipntr(6) + ritzi = ipntr(7) + bounds = ipntr(8) + ldh = ncv + ldq = ncv + iheigr = bounds + ldh + iheigi = iheigr + ldh + ihbds = iheigi + ldh + iuptri = ihbds + ldh + invsub = iuptri + ldh*ncv + ipntr(9) = iheigr + ipntr(10) = iheigi + ipntr(11) = ihbds + ipntr(12) = iuptri + ipntr(13) = invsub + wrr = 1 + wri = ncv + 1 + iwev = wri + ncv +c +c %-----------------------------------------% +c | irr points to the REAL part of the Ritz | +c | values computed by _neigh before | +c | exiting _naup2. | +c | iri points to the IMAGINARY part of the | +c | Ritz values computed by _neigh | +c | before exiting _naup2. | +c | ibd points to the Ritz estimates | +c | computed by _neigh before exiting | +c | _naup2. | +c %-----------------------------------------% +c + irr = ipntr(14)+ncv*ncv + iri = irr+ncv + ibd = iri+ncv +c +c %------------------------------------% +c | RNORM is B-norm of the RESID(1:N). | +c %------------------------------------% +c + rnorm = workl(ih+2) + workl(ih+2) = zero +c + if (msglvl .gt. 2) then + call dvout (logfil, ncv, workl(irr), ndigit, + & '_neupd: Real part of Ritz values passed in from _NAUPD.') + call dvout (logfil, ncv, workl(iri), ndigit, + & '_neupd: Imag part of Ritz values passed in from _NAUPD.') + call dvout (logfil, ncv, workl(ibd), ndigit, + & '_neupd: Ritz estimates passed in from _NAUPD.') + end if +c + if (rvec) then +c + reord = .false. +c +c %---------------------------------------------------% +c | Use the temporary bounds array to store indices | +c | These will be used to mark the select array later | +c %---------------------------------------------------% +c + do 10 j = 1,ncv + workl(bounds+j-1) = j + select(j) = .false. + 10 continue +c +c %-------------------------------------% +c | Select the wanted Ritz values. | +c | Sort the Ritz values so that the | +c | wanted ones appear at the tailing | +c | NEV positions of workl(irr) and | +c | workl(iri). Move the corresponding | +c | error estimates in workl(bound) | +c | accordingly. | +c %-------------------------------------% +c + np = ncv - nev + ishift = 0 + call dngets (ishift , which , nev , + & np , workl(irr), workl(iri), + & workl(bounds), workl , workl(np+1)) +c + if (msglvl .gt. 2) then + call dvout (logfil, ncv, workl(irr), ndigit, + & '_neupd: Real part of Ritz values after calling _NGETS.') + call dvout (logfil, ncv, workl(iri), ndigit, + & '_neupd: Imag part of Ritz values after calling _NGETS.') + call dvout (logfil, ncv, workl(bounds), ndigit, + & '_neupd: Ritz value indices after calling _NGETS.') + end if +c +c %-----------------------------------------------------% +c | Record indices of the converged wanted Ritz values | +c | Mark the select array for possible reordering | +c %-----------------------------------------------------% +c + numcnv = 0 + do 11 j = 1,ncv + temp1 = max(eps23, + & dlapy2 ( workl(irr+ncv-j), workl(iri+ncv-j) )) + jj = workl(bounds + ncv - j) + if (numcnv .lt. nconv .and. + & workl(ibd+jj-1) .le. tol*temp1) then + select(jj) = .true. + numcnv = numcnv + 1 + if (jj .gt. nev) reord = .true. + endif + 11 continue +c +c %-----------------------------------------------------------% +c | Check the count (numcnv) of converged Ritz values with | +c | the number (nconv) reported by dnaupd. If these two | +c | are different then there has probably been an error | +c | caused by incorrect passing of the dnaupd data. | +c %-----------------------------------------------------------% +c + if (msglvl .gt. 2) then + call ivout(logfil, 1, numcnv, ndigit, + & '_neupd: Number of specified eigenvalues') + call ivout(logfil, 1, nconv, ndigit, + & '_neupd: Number of "converged" eigenvalues') + end if +c + if (numcnv .ne. nconv) then + info = -15 + go to 9000 + end if +c +c %-----------------------------------------------------------% +c | Call LAPACK routine dlahqr to compute the real Schur form | +c | of the upper Hessenberg matrix returned by DNAUPD . | +c | Make a copy of the upper Hessenberg matrix. | +c | Initialize the Schur vector matrix Q to the identity. | +c %-----------------------------------------------------------% +c + call dcopy (ldh*ncv, workl(ih), 1, workl(iuptri), 1) + call dlaset ('All', ncv, ncv, + & zero , one, workl(invsub), + & ldq) + call dlahqr (.true., .true. , ncv, + & 1 , ncv , workl(iuptri), + & ldh , workl(iheigr), workl(iheigi), + & 1 , ncv , workl(invsub), + & ldq , ierr) + call dcopy (ncv , workl(invsub+ncv-1), ldq, + & workl(ihbds), 1) +c + if (ierr .ne. 0) then + info = -8 + go to 9000 + end if +c + if (msglvl .gt. 1) then + call dvout (logfil, ncv, workl(iheigr), ndigit, + & '_neupd: Real part of the eigenvalues of H') + call dvout (logfil, ncv, workl(iheigi), ndigit, + & '_neupd: Imaginary part of the Eigenvalues of H') + call dvout (logfil, ncv, workl(ihbds), ndigit, + & '_neupd: Last row of the Schur vector matrix') + if (msglvl .gt. 3) then + call dmout (logfil , ncv, ncv , + & workl(iuptri), ldh, ndigit, + & '_neupd: The upper quasi-triangular matrix ') + end if + end if +c + if (reord) then +c +c %-----------------------------------------------------% +c | Reorder the computed upper quasi-triangular matrix. | +c %-----------------------------------------------------% +c + call dtrsen ('None' , 'V' , + & select , ncv , + & workl(iuptri), ldh , + & workl(invsub), ldq , + & workl(iheigr), workl(iheigi), + & nconv , conds , + & sep , workl(ihbds) , + & ncv , iwork , + & 1 , ierr) +c + if (ierr .eq. 1) then + info = 1 + go to 9000 + end if +c + if (msglvl .gt. 2) then + call dvout (logfil, ncv, workl(iheigr), ndigit, + & '_neupd: Real part of the eigenvalues of H--reordered') + call dvout (logfil, ncv, workl(iheigi), ndigit, + & '_neupd: Imag part of the eigenvalues of H--reordered') + if (msglvl .gt. 3) then + call dmout (logfil , ncv, ncv , + & workl(iuptri), ldq, ndigit, + & '_neupd: Quasi-triangular matrix after re-ordering') + end if + end if +c + end if +c +c %---------------------------------------% +c | Copy the last row of the Schur vector | +c | into workl(ihbds). This will be used | +c | to compute the Ritz estimates of | +c | converged Ritz values. | +c %---------------------------------------% +c + call dcopy (ncv, workl(invsub+ncv-1), ldq, workl(ihbds), 1) +c +c %----------------------------------------------------% +c | Place the computed eigenvalues of H into DR and DI | +c | if a spectral transformation was not used. | +c %----------------------------------------------------% +c + if (type .eq. 'REGULR') then + call dcopy (nconv, workl(iheigr), 1, dr, 1) + call dcopy (nconv, workl(iheigi), 1, di, 1) + end if +c +c %----------------------------------------------------------% +c | Compute the QR factorization of the matrix representing | +c | the wanted invariant subspace located in the first NCONV | +c | columns of workl(invsub,ldq). | +c %----------------------------------------------------------% +c + call dgeqr2 (ncv, nconv , workl(invsub), + & ldq, workev, workev(ncv+1), + & ierr) +c +c %---------------------------------------------------------% +c | * Postmultiply V by Q using dorm2r . | +c | * Copy the first NCONV columns of VQ into Z. | +c | * Postmultiply Z by R. | +c | The N by NCONV matrix Z is now a matrix representation | +c | of the approximate invariant subspace associated with | +c | the Ritz values in workl(iheigr) and workl(iheigi) | +c | The first NCONV columns of V are now approximate Schur | +c | vectors associated with the real upper quasi-triangular | +c | matrix of order NCONV in workl(iuptri) | +c %---------------------------------------------------------% +c + call dorm2r ('Right', 'Notranspose', n , + & ncv , nconv , workl(invsub), + & ldq , workev , v , + & ldv , workd(n+1) , ierr) + call dlacpy ('All', n, nconv, v, ldv, z, ldz) +c + do 20 j=1, nconv +c +c %---------------------------------------------------% +c | Perform both a column and row scaling if the | +c | diagonal element of workl(invsub,ldq) is negative | +c | I'm lazy and don't take advantage of the upper | +c | quasi-triangular form of workl(iuptri,ldq) | +c | Note that since Q is orthogonal, R is a diagonal | +c | matrix consisting of plus or minus ones | +c %---------------------------------------------------% +c + if (workl(invsub+(j-1)*ldq+j-1) .lt. zero) then + call dscal (nconv, -one, workl(iuptri+j-1), ldq) + call dscal (nconv, -one, workl(iuptri+(j-1)*ldq), 1) + end if +c + 20 continue +c + if (howmny .eq. 'A') then +c +c %--------------------------------------------% +c | Compute the NCONV wanted eigenvectors of T | +c | located in workl(iuptri,ldq). | +c %--------------------------------------------% +c + do 30 j=1, ncv + if (j .le. nconv) then + select(j) = .true. + else + select(j) = .false. + end if + 30 continue +c + call dtrevc ('Right', 'Select' , select , + & ncv , workl(iuptri), ldq , + & vl , 1 , workl(invsub), + & ldq , ncv , outncv , + & workev , ierr) +c + if (ierr .ne. 0) then + info = -9 + go to 9000 + end if +c +c %------------------------------------------------% +c | Scale the returning eigenvectors so that their | +c | Euclidean norms are all one. LAPACK subroutine | +c | dtrevc returns each eigenvector normalized so | +c | that the element of largest magnitude has | +c | magnitude 1; | +c %------------------------------------------------% +c + iconj = 0 + do 40 j=1, nconv +c + if ( workl(iheigi+j-1) .eq. zero ) then +c +c %----------------------% +c | real eigenvalue case | +c %----------------------% +c + temp = dnrm2 ( ncv, workl(invsub+(j-1)*ldq), 1 ) + call dscal ( ncv, one / temp, + & workl(invsub+(j-1)*ldq), 1 ) +c + else +c +c %-------------------------------------------% +c | Complex conjugate pair case. Note that | +c | since the real and imaginary part of | +c | the eigenvector are stored in consecutive | +c | columns, we further normalize by the | +c | square root of two. | +c %-------------------------------------------% +c + if (iconj .eq. 0) then + temp = dlapy2 (dnrm2 (ncv, + & workl(invsub+(j-1)*ldq), + & 1), + & dnrm2 (ncv, + & workl(invsub+j*ldq), + & 1)) + call dscal (ncv, one/temp, + & workl(invsub+(j-1)*ldq), 1 ) + call dscal (ncv, one/temp, + & workl(invsub+j*ldq), 1 ) + iconj = 1 + else + iconj = 0 + end if +c + end if +c + 40 continue +c + call dgemv ('T', ncv, nconv, one, workl(invsub), + & ldq, workl(ihbds), 1, zero, workev, 1) +c + iconj = 0 + do 45 j=1, nconv + if (workl(iheigi+j-1) .ne. zero) then +c +c %-------------------------------------------% +c | Complex conjugate pair case. Note that | +c | since the real and imaginary part of | +c | the eigenvector are stored in consecutive | +c %-------------------------------------------% +c + if (iconj .eq. 0) then + workev(j) = dlapy2 (workev(j), workev(j+1)) + workev(j+1) = workev(j) + iconj = 1 + else + iconj = 0 + end if + end if + 45 continue +c + if (msglvl .gt. 2) then + call dcopy (ncv, workl(invsub+ncv-1), ldq, + & workl(ihbds), 1) + call dvout (logfil, ncv, workl(ihbds), ndigit, + & '_neupd: Last row of the eigenvector matrix for T') + if (msglvl .gt. 3) then + call dmout (logfil, ncv, ncv, workl(invsub), ldq, + & ndigit, '_neupd: The eigenvector matrix for T') + end if + end if +c +c %---------------------------------------% +c | Copy Ritz estimates into workl(ihbds) | +c %---------------------------------------% +c + call dcopy (nconv, workev, 1, workl(ihbds), 1) +c +c %---------------------------------------------------------% +c | Compute the QR factorization of the eigenvector matrix | +c | associated with leading portion of T in the first NCONV | +c | columns of workl(invsub,ldq). | +c %---------------------------------------------------------% +c + call dgeqr2 (ncv, nconv , workl(invsub), + & ldq, workev, workev(ncv+1), + & ierr) +c +c %----------------------------------------------% +c | * Postmultiply Z by Q. | +c | * Postmultiply Z by R. | +c | The N by NCONV matrix Z is now contains the | +c | Ritz vectors associated with the Ritz values | +c | in workl(iheigr) and workl(iheigi). | +c %----------------------------------------------% +c + call dorm2r ('Right', 'Notranspose', n , + & ncv , nconv , workl(invsub), + & ldq , workev , z , + & ldz , workd(n+1) , ierr) +c + call dtrmm ('Right' , 'Upper' , 'No transpose', + & 'Non-unit', n , nconv , + & one , workl(invsub), ldq , + & z , ldz) +c + end if +c + else +c +c %------------------------------------------------------% +c | An approximate invariant subspace is not needed. | +c | Place the Ritz values computed DNAUPD into DR and DI | +c %------------------------------------------------------% +c + call dcopy (nconv, workl(ritzr), 1, dr, 1) + call dcopy (nconv, workl(ritzi), 1, di, 1) + call dcopy (nconv, workl(ritzr), 1, workl(iheigr), 1) + call dcopy (nconv, workl(ritzi), 1, workl(iheigi), 1) + call dcopy (nconv, workl(bounds), 1, workl(ihbds), 1) + end if +c +c %------------------------------------------------% +c | Transform the Ritz values and possibly vectors | +c | and corresponding error bounds of OP to those | +c | of A*x = lambda*B*x. | +c %------------------------------------------------% +c + if (type .eq. 'REGULR') then +c + if (rvec) + & call dscal (ncv, rnorm, workl(ihbds), 1) +c + else +c +c %---------------------------------------% +c | A spectral transformation was used. | +c | * Determine the Ritz estimates of the | +c | Ritz values in the original system. | +c %---------------------------------------% +c + if (type .eq. 'SHIFTI') then +c + if (rvec) + & call dscal (ncv, rnorm, workl(ihbds), 1) +c + do 50 k=1, ncv + temp = dlapy2 ( workl(iheigr+k-1), + & workl(iheigi+k-1) ) + workl(ihbds+k-1) = abs( workl(ihbds+k-1) ) + & / temp / temp + 50 continue +c + else if (type .eq. 'REALPT') then +c + do 60 k=1, ncv + 60 continue +c + else if (type .eq. 'IMAGPT') then +c + do 70 k=1, ncv + 70 continue +c + end if +c +c %-----------------------------------------------------------% +c | * Transform the Ritz values back to the original system. | +c | For TYPE = 'SHIFTI' the transformation is | +c | lambda = 1/theta + sigma | +c | For TYPE = 'REALPT' or 'IMAGPT' the user must from | +c | Rayleigh quotients or a projection. See remark 3 above.| +c | NOTES: | +c | *The Ritz vectors are not affected by the transformation. | +c %-----------------------------------------------------------% +c + if (type .eq. 'SHIFTI') then +c + do 80 k=1, ncv + temp = dlapy2 ( workl(iheigr+k-1), + & workl(iheigi+k-1) ) + workl(iheigr+k-1) = workl(iheigr+k-1)/temp/temp + & + sigmar + workl(iheigi+k-1) = -workl(iheigi+k-1)/temp/temp + & + sigmai + 80 continue +c + call dcopy (nconv, workl(iheigr), 1, dr, 1) + call dcopy (nconv, workl(iheigi), 1, di, 1) +c + else if (type .eq. 'REALPT' .or. type .eq. 'IMAGPT') then +c + call dcopy (nconv, workl(iheigr), 1, dr, 1) + call dcopy (nconv, workl(iheigi), 1, di, 1) +c + end if +c + end if +c + if (type .eq. 'SHIFTI' .and. msglvl .gt. 1) then + call dvout (logfil, nconv, dr, ndigit, + & '_neupd: Untransformed real part of the Ritz valuess.') + call dvout (logfil, nconv, di, ndigit, + & '_neupd: Untransformed imag part of the Ritz valuess.') + call dvout (logfil, nconv, workl(ihbds), ndigit, + & '_neupd: Ritz estimates of untransformed Ritz values.') + else if (type .eq. 'REGULR' .and. msglvl .gt. 1) then + call dvout (logfil, nconv, dr, ndigit, + & '_neupd: Real parts of converged Ritz values.') + call dvout (logfil, nconv, di, ndigit, + & '_neupd: Imag parts of converged Ritz values.') + call dvout (logfil, nconv, workl(ihbds), ndigit, + & '_neupd: Associated Ritz estimates.') + end if +c +c %-------------------------------------------------% +c | Eigenvector Purification step. Formally perform | +c | one of inverse subspace iteration. Only used | +c | for MODE = 2. | +c %-------------------------------------------------% +c + if (rvec .and. howmny .eq. 'A' .and. type .eq. 'SHIFTI') then +c +c %------------------------------------------------% +c | Purify the computed Ritz vectors by adding a | +c | little bit of the residual vector: | +c | T | +c | resid(:)*( e s ) / theta | +c | NCV | +c | where H s = s theta. Remember that when theta | +c | has nonzero imaginary part, the corresponding | +c | Ritz vector is stored across two columns of Z. | +c %------------------------------------------------% +c + iconj = 0 + do 110 j=1, nconv + if (workl(iheigi+j-1) .eq. zero) then + workev(j) = workl(invsub+(j-1)*ldq+ncv-1) / + & workl(iheigr+j-1) + else if (iconj .eq. 0) then + temp = dlapy2 ( workl(iheigr+j-1), workl(iheigi+j-1) ) + workev(j) = ( workl(invsub+(j-1)*ldq+ncv-1) * + & workl(iheigr+j-1) + + & workl(invsub+j*ldq+ncv-1) * + & workl(iheigi+j-1) ) / temp / temp + workev(j+1) = ( workl(invsub+j*ldq+ncv-1) * + & workl(iheigr+j-1) - + & workl(invsub+(j-1)*ldq+ncv-1) * + & workl(iheigi+j-1) ) / temp / temp + iconj = 1 + else + iconj = 0 + end if + 110 continue +c +c %---------------------------------------% +c | Perform a rank one update to Z and | +c | purify all the Ritz vectors together. | +c %---------------------------------------% +c + call dger (n, nconv, one, resid, 1, workev, 1, z, ldz) +c + end if +c + 9000 continue +c + return +c +c %---------------% +c | End of DNEUPD | +c %---------------% +c + end