File: bdiag.f

package info (click to toggle)
scilab 4.0-12
  • links: PTS
  • area: non-free
  • in suites: etch, etch-m68k
  • size: 100,640 kB
  • ctags: 57,333
  • sloc: ansic: 377,889; fortran: 242,862; xml: 179,819; tcl: 42,062; sh: 10,593; ml: 9,441; makefile: 4,377; cpp: 1,354; java: 621; csh: 260; yacc: 247; perl: 130; lex: 126; asm: 72; lisp: 30
file content (511 lines) | stat: -rw-r--r-- 12,717 bytes parent folder | download | duplicates (6)
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
      subroutine bdiag(lda,n,a,epsshr,rmax,er,ei,bs,x,xi,scale,
     1                 job,fail)
c
c!purpose
c   dbdiag reduces a matrix a to block diagonal form by first
c   reducing it to quasi-triangular form by hqror2 and then by
c   solving the matrix equation -a11*p+p*a22=a12 to introduce zeros
c   above the diagonal.
c   right transformation is factored : p*d*u*y ;where:
c     p is a permutation matrix and d positive diagonal matrix
c     u is orthogonal and y block upper triangular with identity
c     blocks on the diagonal
c
c!calling sequence
c
c     subroutine bdiag(lda,n,a,epsshr,rmax,er,ei,bs,x,xi,scale,
c    * job,fail)
c
c     integer lda, n,  bs, job
c     double precision a,er,ei,x,xi,rmax,epsshr,scale
c     dimension a(lda,n),x(lda,n),xi(lda,n),er(n),ei(n),bs(n)
c     dimension scale(n)
c     logical fail
c
c   starred parameters are altered by the subroutine
c
c
c  *a        an array that initially contains the m x n matrix
c            to be reduced. on return,  see job
c
c   lda      the leading dimension of array a. and array x,xi.
c
c   n        the order of the matrices a,x,xi
c
c   epsshr   the minimal conditionnement allowed for linear sytems
c
c   rmax     the maximum size allowed for any element of the
c            transformations.
c
c  *er       a singly subscripted real array containing the real
c            parts of the eigenvalues.
c
c  *ei       a singly subscripted real array containg the imaginary
c            parts of the eigenvalues.
c
c  *bs       a singly subscripted integer array that contains block
c            structure information.  if there is a block of order
c            k starting at a(l,l) in the output matrix a, then
c            bs(l) contains the positive integer k, bs(l+1) contains
c            -(k-1), bs(la+2) = -(k-2), ..., bs(l+k-1) = -1.
c            thus a positive integer in the l-th entry of bs
c            indicates a new block of order bs(l) starting at a(l,l).
c
c  *x        contains,  either right reducing transformation u*y,
c            either orthogonal tranformation u (see job)
c
c  *xi       xi contains the inverse reducing matrix transformation
c               or y matrix (see job)
c
c  *scale    contains the scale factor and definitions of p size(n)
c
c   job      integer parametre specifying outputed transformations
c            job=0 : a contains block diagonal form
c                    x right transformation
c                    xi dummy variable
c            job=1:like job=0 and xi contain x**-1
c            job=2 a contains block diagonal form
c                  x contains u and xi contain y
c            job=3: a contains:
c                      -block diagonal form in the diagonal blocks
c                      -a factorisation of y in the upper triangular
c                   x contains u
c                   xi dummy
c  *fail     a logical variable which is false on normal return and
c            true if there is any error in bdiag.
c
c
c!auxiliary routines
c     orthes ortran (eispack)
c     hqror2 exch split (eispack.extensions)
c     dset ddot (blas)
c     real dble abs (fortran)
c     shrslv dad
c
c!
c
      integer lda, n,  bs, job
      double precision a,er,ei,x,xi,rmax,epsshr,scale(n)
      dimension a(lda,n),x(lda,n),xi(lda,n),er(n),ei(n),bs(n)
      logical fail,fails
c
      double precision c,cav,d,e1,e2,rav,temp,zero,one,mone,ddot,eps
      double precision dlamch
      integer da11,da22,i,j,k,km1,km2,l11,l22,l22m1,nk,ino
      integer low,igh
      data zero, one, mone /0.0d+0,1.0d+0,-1.0d+0/
c
c
      fail = .false.
      fails= .true.
      ino  =  -1
c
c     compute eps the l1 norm of the a matrix
c
      eps=0.0d0
      do 11 j=1,n
         temp=0.0d0
         do 10 i=1,n
            temp=temp+abs(a(i,j))
 10      continue
         eps=max(eps,temp)
 11   continue
      if (eps.eq.0.0d0) eps=1.0d0
      eps=dlamch('p')*eps


c
c     convert a to upper hessenberg form.
c
      call balanc(lda, n,   a, low, igh, scale)
      call orthes(lda, n, low, igh,   a, er)
      call ortran(lda, n, low, igh,   a, er, x)
c
c     convert a to quasi-upper triangular form by qr method.
c
      call hqror2(lda,n,1,n,a,er,ei,x,ierr,21)
c
c     check to see if hqror2 failed in computing any eigenvalue
c
c
      if(ierr.gt.1) goto 600
c
c     reduce a to block diagonal form
c
c
c     segment a into 4 matrices: a11, a da11 x da11 block
c     whose (1,1)-element is at a(l11,l11))  a22, a da22 x da22
c     block whose (1,1)-element is at a(l22,l22)) a12,
c     a da11 x da22 block whose (1,1)-element is at a(l11,l22))
c     and a21, a da22 x da11 block = 0 whose (1,1)-
c     element is at a(l22,l11).
c
c
c
c     this loop uses l11 as loop index and splits off a block
c     starting at a(l11,l11).
c
c
      l11 = 1
   40 continue
      if (l11.gt.n) go to 350
      l22 = l11
c
c       this loop uses da11 as loop variable and attempts to split
c       off a block of size da11 starting at a(l11,l11)
c
   50 continue
      if (l22.ne.l11) go to 60
      da11 = 1
      if(l11 .eq. n) go to 51
      if(abs(a(l11+1,l11)) .gt.eps ) then
         da11 = 2
      endif
   51 continue
      l22 = l11 + da11
      l22m1 = l22 - 1
      go to 240
   60 continue
c
c
c           compute the average of the eigenvalues in a11
c
      rav = zero
      cav = zero
      do 70 i=l11,l22m1
         rav = rav + er(i)
         cav = cav + abs(ei(i))
   70 continue
      rav = rav/dble(real(da11)   )
      cav = cav/dble(real(da11)   )
c
c           loop on eigenvalues of a22 to find the one closest to the av
c
      d = (rav-er(l22))**2 + (cav-ei(l22))**2
      k = l22
      l = l22 + 1
      if(l22 .eq. n) go to 71
      if(abs(a(l22+1,l22)) .gt. eps) l = l22 + 2
   71 continue
   80 continue
      if (l.gt.n) go to 100
      c = (rav-er(l))**2 + (cav-ei(l))**2
      if (c.ge.d) go to 90
      k = l
      d = c
   90 continue
      l = l + 1
      if(l.gt.n) go to 100
      if (abs(a(l,l-1)).gt.eps) l=l+1
      go to 80
  100 continue
c
c
c           loop to move the eigenvalue just located
c           into first position of block a22.
c
      if (k.eq.n) goto 105
      if (abs(a(k+1,k)).gt.eps) go to 150
c
c             the block we're moving to add to a11 is a 1 x 1
c
  105 nk = 1
  110 continue
      if (k.eq.l22) go to 230
      km1 = k - 1
      if (abs(a(km1,k-2)).lt.eps) go to 140
c
c             we're swapping the closest block with a 2 x 2
c
      km2 = k - 2
      call exch(lda,n,a, x, km2, 2, 1)
c
c             try to split this block into 2 real eigenvalues
c
      call split(a, x, n, km1, e1, e2, lda, lda)
      if (a(k,km1).eq.zero) go to 120
c
c             block is still complex.
c
      er(km2) = er(k)
      ei(km2) = zero
      er(k) = e1
      er(km1) = e1
      ei(km1) = e2
      ei(k) = -e2
      go to 130
c
c             complex block split into two real eigenvalues.
c
  120 continue
      er(km2) = er(k)
      er(km1) = e1
      er(k) = e2
      ei(km2) = zero
      ei(km1) = zero
  130 k = km2
      if (k.le.l22) go to 230
      go to 110
c
c
c             we're swapping the closest block with a 1 x 1.
c
  140 continue
      call exch(lda,n,a, x, km1, 1, 1)
      temp = er(k)
      er(k) = er(km1)
      er(km1) = temp
      k = km1
      if (k.le.l22) go to 230
      go to 110
c
c             the block we're moving to add to a11 is a 2 x 2.
c
  150 continue
      nk = 2
  160 continue
      if (k.eq.l22) go to 230
      km1 = k - 1
      if (abs(a(km1,k-2)).lt.eps) goto 190
c
c             we're swapping the closest block with a 2 x 2 block.
c
      km2 = k - 2
      call exch(lda,n,a, x, km2, 2, 2)
c
c             try to split swapped block into two reals.
c
      call split(a, x, n, k, e1, e2, lda, lda)
      er(km2) = er(k)
      er(km1) = er(k+1)
      ei(km2) = ei(k)
      ei(km1) = ei(k+1)
      if (a(k+1,k).eq.zero) go to 170
c
c             still complex block.
c
      er(k) = e1
      er(k+1) = e1
      ei(k) = e2
      ei(k+1) = -e2
      go to 180
c
c             two real roots.
c
  170 continue
      er(k) = e1
      er(k+1) = e2
      ei(k) = zero
      ei(k+1) = zero
  180 continue
      k = km2
      if (k.eq.l22) go to 210
      go to 160
c
c             we're swapping the closest block with a 1 x 1.
c
  190 continue
      call exch(lda,n,a, x, km1, 1, 2)
      er(k+1) = er(km1)
      er(km1) = er(k)
      ei(km1) = ei(k)
      ei(k) = ei(k+1)
      ei(k+1) = zero
      go to 200
c
  200 continue
      k = km1
      if (k.eq.l22) go to 210
      go to 160
c
c             try to split relocated complex block.
c
  210 continue
      call split(a, x, n, k, e1, e2, lda, lda)
      if (a(k+1,k).eq.zero) go to 220
c
c             still complex.
c
      er(k) = e1
      er(k+1) = e1
      ei(k) = e2
      ei(k+1) = -e2
      go to 230
c
c             split into two real eigenvalues.
c
  220 continue
      er(k) = e1
      er(k+1) = e2
      ei(k) = zero
      ei(k+1) = zero
c
  230 continue
      da11 = da11 + nk
      l22 = l11 + da11
      l22m1 = l22 - 1
  240 continue
      if (l22.gt.n) go to 290
c
c       attempt to split off a block of size da11.
c
      da22 = n - l22 + 1
c
c       save a12 in its transpose form in block a21.
c
      do 260 j=l11,l22m1
         do 250 i=l22,n
            a(i,j) = a(j,i)
  250    continue
  260 continue
c
c
c       convert a11 to lower quasi-triangular and multiply it by -1 and
c       a12 appropriately (for solving -a11*p+p*a22=a12).
c
      call dad(a, lda, l11, l22m1, l11, n, one, 0)
      call dad(a, lda, l11, l22m1, l11, l22m1, mone, 1)
c
c       solve -a11*p + p*a22 = a12.
c
      call shrslv(a(l11,l11), a(l22,l22), a(l11,l22), da11,
     * da22, lda, lda, lda, eps,epsshr,rmax, fails)
      if (.not.fails) go to 290
c
c       change a11 back to upper quasi-triangular.
c
      call dad(a, lda, l11, l22m1, l11, l22m1, one, 1)
      call dad(a, lda, l11, l22m1, l11, l22m1, mone, 0)
c
c       was unable to solve for p - try again
c
c
c       move saved a12 back into its correct position.
c
      do 280 j=l11,l22m1
         do 270 i=l22,n
            a(j,i) = a(i,j)
            a(i,j) = zero
  270    continue
  280 continue
c
c
      go to 50
  290 continue
c
c     change solution to p to proper form.
c
      if (l22.gt.n) go to 300
      call dad(a, lda, l11, l22m1, l11, n, one, 0)
      call dad(a, lda, l11, l22m1, l11, l22m1, mone, 1)

c
c     store block size in array bs.
c
  300 bs(l11) = da11
      j = da11 - 1
      if (j.eq.0) go to 320
      do 310 i=1,j
         l11pi = l11 + i
         bs(l11pi) = -(da11-i)
  310 continue
  320 continue
      l11 = l22
      go to 40
  350 continue
      fail=.false.
c
c     set transformations matrices as required
c
      if(job.eq.3) return
c
c compute inverse transformation
      if(job.ne.1) goto 450
      do 410 i=1,n
      do 410 j=1,n
      xi(i,j)=x(j,i)
  410 continue
      l22=1
  420 l11=l22
      l22=l11+bs(l11)
      if(l22.gt.n) goto 431
      l22m1=l22-1
      do 430 i=l11,l22m1
      do 430 j=1,n
      xi(i,j)=xi(i,j)-ddot(n-l22m1,a(i,l22),lda,xi(l22,j),1)
  430 continue
      goto 420
c in-lines back-tranfc in-lines right transformations of xi
  431 continue
      if (igh .ne. low) then
         do 435 j=low,igh
            temp=1.0d+00/scale(j)
            do 434 i=1,n
               xi(i,j)=xi(i,j)*temp
  434       continue
  435    continue
      endif
      do 445 ii=1,n
         i=ii
         if (i.ge.low .and. i.le.igh) goto 445
         if (i.lt.low) i=low-ii
         k=scale(i)
         if (k.eq.i) goto 445
         do 444 j=1,n
            temp=xi(j,i)
            xi(j,i)=xi(j,k)
            xi(j,k)=temp
  444    continue
  445 continue
c
  450 continue
      if(job.eq.2) goto 500
c compute right transformation
      l22=1
  460 l11=l22
      l22=l11+bs(l11)
      if(l22.gt.n) goto 480
      do 470 j=l22,n
      do 470 i=1,n
      x(i,j)=x(i,j)+ddot(l22-l11,x(i,l11),lda,a(l11,j),1)
  470 continue
      goto 460
c
  480 continue
      call balbak( lda, n, low, igh, scale, n, x)
      goto 550
c
c extract non orthogonal tranformation from a
  500 continue
      do 510 j=1,n
      call dset(n,zero,xi(1,j),1)
  510 continue
      call dset(n,one,xi(1,1),lda+1)
      l22=1
  520 l11=l22
      if(l11.gt.n) goto 550
      l22=l11+bs(l11)
      do 530 j=l22,n
      do 530 i=1,n
      xi(i,j)=xi(i,j)+ddot(l22-l11,xi(i,l11),lda,a(l11,j),1)
  530 continue
      goto 520
c
c set zeros in the matrix a
  550 l11=1
  560 l22=l11+bs(l11)
      if(l22.gt.n) return
      l22m1=l22-1
      do 570 j=l11,l22m1
      call dset(n-l22m1,zero,a(j,l22),lda)
      call dset(n-l22m1,zero,a(l22,j),1)
  570 continue
      l11=l22
      goto 560
c
c     error return.
c
  600 continue
      fail = .true.
c
      end