summaryrefslogtreecommitdiff
path: root/modules/cacsd/src/slicot/inva.f
blob: 369e0809085366087a6ee7600d806bc8a8e2f95a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
      subroutine inva(nmax,n,a,z,ftest,eps,ndim,fail,ind)
      integer nmax,n,ftest,ndim,ind(n)
      logical fail
      double precision a(nmax,n),z(nmax,n),eps
c!purpose
c  given the upper real schur matrix a
c  with 1x1 or 2x2 diagonal blocks, this routine reorders the diagonal
c  blocks along with their generalized eigenvalues by constructing equi-
c  valence transformation. the transformation is also
c  performed on the given (initial) transformation z (resulting from a
c  possible previous step or initialized with the identity matrix).
c  after reordering, the eigenvalues inside the region specified by the
c  function ftest appear at the top. if ndim is their number then the
c  ndim first columns of z span the requested subspace.
c!calling sequence
c
c     subroutine inva (nmax,n,a,z,ftest,eps,ndim,fail,ind)
c     integer nmax,n,ftest,ndim,ind(n)
c     logical fail
c     double precision a(nmax,n),z(nmax,n),eps
c
c     nmax     the first dimension of a and z
c     n        the order of a and z
c    *a        the matrix whose blocks are to be reordered.
c    *z        upon return this array is multiplied by the column
c              transformation z.
c     ftest(ls,alpha,beta,s,p) an integer function describing the
c              spectrum of the invariant subspace to be computed:
c              when ls=1 ftest checks if alpha/beta is in that spectrum
c              when ls=2 ftest checks if the two complex conjugate
c              roots with sum s and product p are in that spectrum
c              if the answer is positive, ftest=1, otherwise ftest=-1
c     eps      the required absolute accuracy of the result
c    *ndim     an integer giving the dimension of the computed
c              invariant subspace
c    *fail     a logical variable which is false on a normal return,
c              true otherwise (when exchng fails)
c    *ind      an integer working array of dimension at least n
c
c!auxiliary routines
c     exchng
c     ftest  (user defined)
c!
c Copyright SLICOT
      external ftest
      integer l,ls,ls1,ls2,l1,ll,num,is,l2i,l2k,i,k,ii,istep,ifirst
      double precision s,p,alpha,beta
      integer         iero
      common /ierinv/ iero
      
      iero=0
      fail=.false.
      ndim=0
      num=0
      l=0
      ls=1
c ** construct array ind(i) where :
c **      abs(ind(i)) is the size of the block i
c **     sign(ind(i)) indicates the location of its eigenvalues
c **                  (as determined by ftest).
c ** num is the number of elements in this array
      do 40 ll=1,n
        l=l+ls
        if(l.gt.n) go to 50
        l1=l+1
        if(l1.gt.n) go to 20
        if(a(l1,l).eq.0.0d+0) go to 20
c  here a 2x2  block is checked *
        ls=2
        s=a(l,l)+a(l1,l1)
        p=a(l,l)*a(l1,l1)-a(l,l1)*a(l1,l)
        is=ftest(ls,alpha,beta,s,p)
        if(iero.gt.0) return
        go to 30
c  here a 1x1  block is checked *
 20     ls=1
        is=ftest(ls,a(l,l),1.0d+0,s,p)
        if(iero.gt.0) return
 30     num=num+1
        if(is.eq.1) ndim=ndim+ls
 40     ind(num)=ls*is
c **  reorder blocks such that those with positive value
c **    of ind(.) appear first.
 50   l2i=1
      do 90 i=1,num
        if(ind(i).gt.0) go to 90
c  if a negative ind(i) is encountered, then search for the first
c  positive ind(k) following on it
        l2k=l2i
        do 60 k=i,num
          if(ind(k).lt.0) go to 60
          go to 70
 60       l2k=l2k-ind(k)
c  if there are no positive indices following on a negative one
c  then stop
        go to 100
c  if a positive ind(k) follows on a negative ind(i) then
c  interchange block k before block i by performing k-i swaps
 70     istep=k-i
        ls2=ind(k)
        l=l2k
        do 80 ii=1,istep
          ifirst=k-ii
          ls1=-ind(ifirst)
          l=l-ls1
c          call exchng(a,z,n,l,ls1,ls2,eps,fail,nmax,nmax)
            call exch(nmax,n,a,z,l,ls1,ls2)
          if (fail) return
 80       ind(ifirst+1)=ind(ifirst)
        ind(i)=ls2
 90     l2i=l2i+ind(i)
 100  fail=.false.
      return
      end