diff libcruft/arpack/src/dsapps.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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libcruft/arpack/src/dsapps.f	Fri Jan 28 14:04:33 2011 -0500
@@ -0,0 +1,516 @@
+c-----------------------------------------------------------------------
+c\BeginDoc
+c
+c\Name: dsapps
+c
+c\Description:
+c  Given the Arnoldi factorization
+c
+c     A*V_{k} - V_{k}*H_{k} = r_{k+p}*e_{k+p}^T,
+c
+c  apply NP shifts implicitly resulting in
+c
+c     A*(V_{k}*Q) - (V_{k}*Q)*(Q^T* H_{k}*Q) = r_{k+p}*e_{k+p}^T * Q
+c
+c  where Q is an orthogonal matrix of order KEV+NP. Q is the product of 
+c  rotations resulting from the NP bulge chasing sweeps.  The updated Arnoldi 
+c  factorization becomes:
+c
+c     A*VNEW_{k} - VNEW_{k}*HNEW_{k} = rnew_{k}*e_{k}^T.
+c
+c\Usage:
+c  call dsapps
+c     ( N, KEV, NP, SHIFT, V, LDV, H, LDH, RESID, Q, LDQ, WORKD )
+c
+c\Arguments
+c  N       Integer.  (INPUT)
+c          Problem size, i.e. dimension of matrix A.
+c
+c  KEV     Integer.  (INPUT)
+c          INPUT: KEV+NP is the size of the input matrix H.
+c          OUTPUT: KEV is the size of the updated matrix HNEW.
+c
+c  NP      Integer.  (INPUT)
+c          Number of implicit shifts to be applied.
+c
+c  SHIFT   Double precision array of length NP.  (INPUT)
+c          The shifts to be applied.
+c
+c  V       Double precision N by (KEV+NP) array.  (INPUT/OUTPUT)
+c          INPUT: V contains the current KEV+NP Arnoldi vectors.
+c          OUTPUT: VNEW = V(1:n,1:KEV); the updated Arnoldi vectors
+c          are in the first KEV columns of V.
+c
+c  LDV     Integer.  (INPUT)
+c          Leading dimension of V exactly as declared in the calling
+c          program.
+c
+c  H       Double precision (KEV+NP) by 2 array.  (INPUT/OUTPUT)
+c          INPUT: H contains the symmetric tridiagonal matrix of the
+c          Arnoldi factorization with the subdiagonal in the 1st column
+c          starting at H(2,1) and the main diagonal in the 2nd column.
+c          OUTPUT: H contains the updated tridiagonal matrix in the 
+c          KEV leading submatrix.
+c
+c  LDH     Integer.  (INPUT)
+c          Leading dimension of H exactly as declared in the calling
+c          program.
+c
+c  RESID   Double precision array of length (N).  (INPUT/OUTPUT)
+c          INPUT: RESID contains the the residual vector r_{k+p}.
+c          OUTPUT: RESID is the updated residual vector rnew_{k}.
+c
+c  Q       Double precision KEV+NP by KEV+NP work array.  (WORKSPACE)
+c          Work array used to accumulate the rotations during the bulge
+c          chase sweep.
+c
+c  LDQ     Integer.  (INPUT)
+c          Leading dimension of Q exactly as declared in the calling
+c          program.
+c
+c  WORKD   Double precision work array of length 2*N.  (WORKSPACE)
+c          Distributed array used in the application of the accumulated
+c          orthogonal matrix Q.
+c
+c\EndDoc
+c
+c-----------------------------------------------------------------------
+c
+c\BeginLib
+c
+c\Local variables:
+c     xxxxxx  real
+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
+c\Routines called:
+c     ivout   ARPACK utility routine that prints integers. 
+c     arscnd  ARPACK utility routine for timing.
+c     dvout   ARPACK utility routine that prints vectors.
+c     dlamch  LAPACK routine that determines machine constants.
+c     dlartg  LAPACK Givens rotation construction routine.
+c     dlacpy  LAPACK matrix copy routine.
+c     dlaset  LAPACK matrix initialization routine.
+c     dgemv   Level 2 BLAS routine for matrix vector multiplication.
+c     daxpy   Level 1 BLAS that computes a vector triad.
+c     dcopy   Level 1 BLAS that copies one vector to another.
+c     dscal   Level 1 BLAS that scales a vector.
+c
+c\Author
+c     Danny Sorensen               Phuong Vu
+c     Richard Lehoucq              CRPC / Rice University
+c     Dept. of Computational &     Houston, Texas
+c     Applied Mathematics
+c     Rice University           
+c     Houston, Texas            
+c
+c\Revision history:
+c     12/16/93: Version ' 2.4'
+c
+c\SCCS Information: @(#) 
+c FILE: sapps.F   SID: 2.6   DATE OF SID: 3/28/97   RELEASE: 2
+c
+c\Remarks
+c  1. In this version, each shift is applied to all the subblocks of
+c     the tridiagonal matrix H and not just to the submatrix that it 
+c     comes from. This routine assumes that the subdiagonal elements 
+c     of H that are stored in h(1:kev+np,1) are nonegative upon input
+c     and enforce this condition upon output. This version incorporates
+c     deflation. See code for documentation.
+c
+c\EndLib
+c
+c-----------------------------------------------------------------------
+c
+      subroutine dsapps
+     &   ( n, kev, np, shift, v, ldv, h, ldh, resid, q, ldq, workd )
+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
+      integer    kev, ldh, ldq, ldv, n, np
+c
+c     %-----------------%
+c     | Array Arguments |
+c     %-----------------%
+c
+      Double precision
+     &           h(ldh,2), q(ldq,kev+np), resid(n), shift(np), 
+     &           v(ldv,kev+np), workd(2*n)
+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
+      integer    i, iend, istart, itop, j, jj, kplusp, msglvl
+      logical    first
+      Double precision
+     &           a1, a2, a3, a4, big, c, epsmch, f, g, r, s
+      save       epsmch, first
+c
+c
+c     %----------------------%
+c     | External Subroutines |
+c     %----------------------%
+c
+      external   daxpy, dcopy, dscal, dlacpy, dlartg, dlaset, dvout, 
+     &           ivout, arscnd, dgemv
+c
+c     %--------------------%
+c     | External Functions |
+c     %--------------------%
+c
+      Double precision
+     &           dlamch
+      external   dlamch
+c
+c     %----------------------%
+c     | Intrinsics Functions |
+c     %----------------------%
+c
+      intrinsic  abs
+c
+c     %----------------%
+c     | Data statments |
+c     %----------------%
+c
+      data       first / .true. /
+c
+c     %-----------------------%
+c     | Executable Statements |
+c     %-----------------------%
+c
+      if (first) then
+         epsmch = dlamch('Epsilon-Machine')
+         first = .false.
+      end if
+      itop = 1
+c
+c     %-------------------------------%
+c     | Initialize timing statistics  |
+c     | & message level for debugging |
+c     %-------------------------------%
+c
+      call arscnd (t0)
+      msglvl = msapps
+c 
+      kplusp = kev + np 
+c 
+c     %----------------------------------------------%
+c     | Initialize Q to the identity matrix of order |
+c     | kplusp used to accumulate the rotations.     |
+c     %----------------------------------------------%
+c
+      call dlaset ('All', kplusp, kplusp, zero, one, q, ldq)
+c
+c     %----------------------------------------------%
+c     | Quick return if there are no shifts to apply |
+c     %----------------------------------------------%
+c
+      if (np .eq. 0) go to 9000
+c 
+c     %----------------------------------------------------------%
+c     | Apply the np shifts implicitly. Apply each shift to the  |
+c     | whole matrix and not just to the submatrix from which it |
+c     | comes.                                                   |
+c     %----------------------------------------------------------%
+c
+      do 90 jj = 1, np
+c 
+         istart = itop
+c
+c        %----------------------------------------------------------%
+c        | Check for splitting and deflation. Currently we consider |
+c        | an off-diagonal element h(i+1,1) negligible if           |
+c        |         h(i+1,1) .le. epsmch*( |h(i,2)| + |h(i+1,2)| )   |
+c        | for i=1:KEV+NP-1.                                        |
+c        | If above condition tests true then we set h(i+1,1) = 0.  |
+c        | Note that h(1:KEV+NP,1) are assumed to be non negative.  |
+c        %----------------------------------------------------------%
+c
+   20    continue
+c
+c        %------------------------------------------------%
+c        | The following loop exits early if we encounter |
+c        | a negligible off diagonal element.             |
+c        %------------------------------------------------%
+c
+         do 30 i = istart, kplusp-1
+            big   = abs(h(i,2)) + abs(h(i+1,2))
+            if (h(i+1,1) .le. epsmch*big) then
+               if (msglvl .gt. 0) then
+                  call ivout (logfil, 1, i, ndigit, 
+     &                 '_sapps: deflation at row/column no.')
+                  call ivout (logfil, 1, jj, ndigit, 
+     &                 '_sapps: occured before shift number.')
+                  call dvout (logfil, 1, h(i+1,1), ndigit, 
+     &                 '_sapps: the corresponding off diagonal element')
+               end if
+               h(i+1,1) = zero
+               iend = i
+               go to 40
+            end if
+   30    continue
+         iend = kplusp
+   40    continue
+c
+         if (istart .lt. iend) then
+c 
+c           %--------------------------------------------------------%
+c           | Construct the plane rotation G'(istart,istart+1,theta) |
+c           | that attempts to drive h(istart+1,1) to zero.          |
+c           %--------------------------------------------------------%
+c
+             f = h(istart,2) - shift(jj)
+             g = h(istart+1,1)
+             call dlartg (f, g, c, s, r)
+c 
+c            %-------------------------------------------------------%
+c            | Apply rotation to the left and right of H;            |
+c            | H <- G' * H * G,  where G = G(istart,istart+1,theta). |
+c            | This will create a "bulge".                           |
+c            %-------------------------------------------------------%
+c
+             a1 = c*h(istart,2)   + s*h(istart+1,1)
+             a2 = c*h(istart+1,1) + s*h(istart+1,2)
+             a4 = c*h(istart+1,2) - s*h(istart+1,1)
+             a3 = c*h(istart+1,1) - s*h(istart,2) 
+             h(istart,2)   = c*a1 + s*a2
+             h(istart+1,2) = c*a4 - s*a3
+             h(istart+1,1) = c*a3 + s*a4
+c 
+c            %----------------------------------------------------%
+c            | Accumulate the rotation in the matrix Q;  Q <- Q*G |
+c            %----------------------------------------------------%
+c
+             do 60 j = 1, min(istart+jj,kplusp)
+                a1            =   c*q(j,istart) + s*q(j,istart+1)
+                q(j,istart+1) = - s*q(j,istart) + c*q(j,istart+1)
+                q(j,istart)   = a1
+   60        continue
+c
+c
+c            %----------------------------------------------%
+c            | The following loop chases the bulge created. |
+c            | Note that the previous rotation may also be  |
+c            | done within the following loop. But it is    |
+c            | kept separate to make the distinction among  |
+c            | the bulge chasing sweeps and the first plane |
+c            | rotation designed to drive h(istart+1,1) to  |
+c            | zero.                                        |
+c            %----------------------------------------------%
+c
+             do 70 i = istart+1, iend-1
+c 
+c               %----------------------------------------------%
+c               | Construct the plane rotation G'(i,i+1,theta) |
+c               | that zeros the i-th bulge that was created   |
+c               | by G(i-1,i,theta). g represents the bulge.   |
+c               %----------------------------------------------%
+c
+                f = h(i,1)
+                g = s*h(i+1,1)
+c
+c               %----------------------------------%
+c               | Final update with G(i-1,i,theta) |
+c               %----------------------------------%
+c
+                h(i+1,1) = c*h(i+1,1)
+                call dlartg (f, g, c, s, r)
+c
+c               %-------------------------------------------%
+c               | The following ensures that h(1:iend-1,1), |
+c               | the first iend-2 off diagonal of elements |
+c               | H, remain non negative.                   |
+c               %-------------------------------------------%
+c
+                if (r .lt. zero) then
+                   r = -r
+                   c = -c
+                   s = -s
+                end if
+c 
+c               %--------------------------------------------%
+c               | Apply rotation to the left and right of H; |
+c               | H <- G * H * G',  where G = G(i,i+1,theta) |
+c               %--------------------------------------------%
+c
+                h(i,1) = r
+c 
+                a1 = c*h(i,2)   + s*h(i+1,1)
+                a2 = c*h(i+1,1) + s*h(i+1,2)
+                a3 = c*h(i+1,1) - s*h(i,2)
+                a4 = c*h(i+1,2) - s*h(i+1,1)
+c 
+                h(i,2)   = c*a1 + s*a2
+                h(i+1,2) = c*a4 - s*a3
+                h(i+1,1) = c*a3 + s*a4
+c 
+c               %----------------------------------------------------%
+c               | Accumulate the rotation in the matrix Q;  Q <- Q*G |
+c               %----------------------------------------------------%
+c
+                do 50 j = 1, min( i+jj, kplusp )
+                   a1       =   c*q(j,i) + s*q(j,i+1)
+                   q(j,i+1) = - s*q(j,i) + c*q(j,i+1)
+                   q(j,i)   = a1
+   50           continue
+c
+   70        continue
+c
+         end if
+c
+c        %--------------------------%
+c        | Update the block pointer |
+c        %--------------------------%
+c
+         istart = iend + 1
+c
+c        %------------------------------------------%
+c        | Make sure that h(iend,1) is non-negative |
+c        | If not then set h(iend,1) <-- -h(iend,1) |
+c        | and negate the last column of Q.         |
+c        | We have effectively carried out a        |
+c        | similarity on transformation H           |
+c        %------------------------------------------%
+c
+         if (h(iend,1) .lt. zero) then
+             h(iend,1) = -h(iend,1)
+             call dscal(kplusp, -one, q(1,iend), 1)
+         end if
+c
+c        %--------------------------------------------------------%
+c        | Apply the same shift to the next block if there is any |
+c        %--------------------------------------------------------%
+c
+         if (iend .lt. kplusp) go to 20
+c
+c        %-----------------------------------------------------%
+c        | Check if we can increase the the start of the block |
+c        %-----------------------------------------------------%
+c
+         do 80 i = itop, kplusp-1
+            if (h(i+1,1) .gt. zero) go to 90
+            itop  = itop + 1
+   80    continue
+c
+c        %-----------------------------------%
+c        | Finished applying the jj-th shift |
+c        %-----------------------------------%
+c
+   90 continue
+c
+c     %------------------------------------------%
+c     | All shifts have been applied. Check for  |
+c     | more possible deflation that might occur |
+c     | after the last shift is applied.         |                               
+c     %------------------------------------------%
+c
+      do 100 i = itop, kplusp-1
+         big   = abs(h(i,2)) + abs(h(i+1,2))
+         if (h(i+1,1) .le. epsmch*big) then
+            if (msglvl .gt. 0) then
+               call ivout (logfil, 1, i, ndigit, 
+     &              '_sapps: deflation at row/column no.')
+               call dvout (logfil, 1, h(i+1,1), ndigit, 
+     &              '_sapps: the corresponding off diagonal element')
+            end if
+            h(i+1,1) = zero
+         end if
+ 100  continue
+c
+c     %-------------------------------------------------%
+c     | Compute the (kev+1)-st column of (V*Q) and      |
+c     | temporarily store the result in WORKD(N+1:2*N). |
+c     | This is not necessary if h(kev+1,1) = 0.         |
+c     %-------------------------------------------------%
+c
+      if ( h(kev+1,1) .gt. zero ) 
+     &   call dgemv ('N', n, kplusp, one, v, ldv,
+     &                q(1,kev+1), 1, zero, workd(n+1), 1)
+c 
+c     %-------------------------------------------------------%
+c     | Compute column 1 to kev of (V*Q) in backward order    |
+c     | taking advantage that Q is an upper triangular matrix |    
+c     | with lower bandwidth np.                              |
+c     | Place results in v(:,kplusp-kev:kplusp) temporarily.  |
+c     %-------------------------------------------------------%
+c
+      do 130 i = 1, kev
+         call dgemv ('N', n, kplusp-i+1, one, v, ldv,
+     &               q(1,kev-i+1), 1, zero, workd, 1)
+         call dcopy (n, workd, 1, v(1,kplusp-i+1), 1)
+  130 continue
+c
+c     %-------------------------------------------------%
+c     |  Move v(:,kplusp-kev+1:kplusp) into v(:,1:kev). |
+c     %-------------------------------------------------%
+c
+      call dlacpy ('All', n, kev, v(1,np+1), ldv, v, ldv)
+c 
+c     %--------------------------------------------%
+c     | Copy the (kev+1)-st column of (V*Q) in the |
+c     | appropriate place if h(kev+1,1) .ne. zero. |
+c     %--------------------------------------------%
+c
+      if ( h(kev+1,1) .gt. zero ) 
+     &     call dcopy (n, workd(n+1), 1, v(1,kev+1), 1)
+c 
+c     %-------------------------------------%
+c     | Update the residual vector:         |
+c     |    r <- sigmak*r + betak*v(:,kev+1) |
+c     | where                               |
+c     |    sigmak = (e_{kev+p}'*Q)*e_{kev}  |
+c     |    betak = e_{kev+1}'*H*e_{kev}     |
+c     %-------------------------------------%
+c
+      call dscal (n, q(kplusp,kev), resid, 1)
+      if (h(kev+1,1) .gt. zero) 
+     &   call daxpy (n, h(kev+1,1), v(1,kev+1), 1, resid, 1)
+c
+      if (msglvl .gt. 1) then
+         call dvout (logfil, 1, q(kplusp,kev), ndigit, 
+     &      '_sapps: sigmak of the updated residual vector')
+         call dvout (logfil, 1, h(kev+1,1), ndigit, 
+     &      '_sapps: betak of the updated residual vector')
+         call dvout (logfil, kev, h(1,2), ndigit, 
+     &      '_sapps: updated main diagonal of H for next iteration')
+         if (kev .gt. 1) then
+         call dvout (logfil, kev-1, h(2,1), ndigit, 
+     &      '_sapps: updated sub diagonal of H for next iteration')
+         end if
+      end if
+c
+      call arscnd (t1)
+      tsapps = tsapps + (t1 - t0)
+c 
+ 9000 continue 
+      return
+c
+c     %---------------%
+c     | End of dsapps |
+c     %---------------%
+c
+      end