Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/mathlibs/src/arpack/dstqrb.f
5215 views
1
c-----------------------------------------------------------------------
2
c\BeginDoc
3
c
4
c\Name: dstqrb
5
c
6
c\Description:
7
c Computes all eigenvalues and the last component of the eigenvectors
8
c of a symmetric tridiagonal matrix using the implicit QL or QR method.
9
c
10
c This is mostly a modification of the LAPACK routine dsteqr.
11
c See Remarks.
12
c
13
c\Usage:
14
c call dstqrb
15
c ( N, D, E, Z, WORK, INFO )
16
c
17
c\Arguments
18
c N Integer. (INPUT)
19
c The number of rows and columns in the matrix. N >= 0.
20
c
21
c D Double precision array, dimension (N). (INPUT/OUTPUT)
22
c On entry, D contains the diagonal elements of the
23
c tridiagonal matrix.
24
c On exit, D contains the eigenvalues, in ascending order.
25
c If an error exit is made, the eigenvalues are correct
26
c for indices 1,2,...,INFO-1, but they are unordered and
27
c may not be the smallest eigenvalues of the matrix.
28
c
29
c E Double precision array, dimension (N-1). (INPUT/OUTPUT)
30
c On entry, E contains the subdiagonal elements of the
31
c tridiagonal matrix in positions 1 through N-1.
32
c On exit, E has been destroyed.
33
c
34
c Z Double precision array, dimension (N). (OUTPUT)
35
c On exit, Z contains the last row of the orthonormal
36
c eigenvector matrix of the symmetric tridiagonal matrix.
37
c If an error exit is made, Z contains the last row of the
38
c eigenvector matrix associated with the stored eigenvalues.
39
c
40
c WORK Double precision array, dimension (max(1,2*N-2)). (WORKSPACE)
41
c Workspace used in accumulating the transformation for
42
c computing the last components of the eigenvectors.
43
c
44
c INFO Integer. (OUTPUT)
45
c = 0: normal return.
46
c < 0: if INFO = -i, the i-th argument had an illegal value.
47
c > 0: if INFO = +i, the i-th eigenvalue has not converged
48
c after a total of 30*N iterations.
49
c
50
c\Remarks
51
c 1. None.
52
c
53
c-----------------------------------------------------------------------
54
c
55
c\BeginLib
56
c
57
c\Local variables:
58
c xxxxxx real
59
c
60
c\Routines called:
61
c daxpy Level 1 BLAS that computes a vector triad.
62
c dcopy Level 1 BLAS that copies one vector to another.
63
c dswap Level 1 BLAS that swaps the contents of two vectors.
64
c lsame LAPACK character comparison routine.
65
c dlae2 LAPACK routine that computes the eigenvalues of a 2-by-2
66
c symmetric matrix.
67
c dlaev2 LAPACK routine that eigendecomposition of a 2-by-2 symmetric
68
c matrix.
69
c dlamch LAPACK routine that determines machine constants.
70
c dlanst LAPACK routine that computes the norm of a matrix.
71
c dlapy2 LAPACK routine to compute sqrt(x**2+y**2) carefully.
72
c dlartg LAPACK Givens rotation construction routine.
73
c dlascl LAPACK routine for careful scaling of a matrix.
74
c dlaset LAPACK matrix initialization routine.
75
c dlasr LAPACK routine that applies an orthogonal transformation to
76
c a matrix.
77
c dlasrt LAPACK sorting routine.
78
c dsteqr LAPACK routine that computes eigenvalues and eigenvectors
79
c of a symmetric tridiagonal matrix.
80
c xerbla LAPACK error handler routine.
81
c
82
c\Authors
83
c Danny Sorensen Phuong Vu
84
c Richard Lehoucq CRPC / Rice University
85
c Dept. of Computational & Houston, Texas
86
c Applied Mathematics
87
c Rice University
88
c Houston, Texas
89
c
90
c\SCCS Information: @(#)
91
c FILE: stqrb.F SID: 2.5 DATE OF SID: 8/27/96 RELEASE: 2
92
c
93
c\Remarks
94
c 1. Starting with version 2.5, this routine is a modified version
95
c of LAPACK version 2.0 subroutine SSTEQR. No lines are deleted,
96
c only commeted out and new lines inserted.
97
c All lines commented out have "c$$$" at the beginning.
98
c Note that the LAPACK version 1.0 subroutine SSTEQR contained
99
c bugs.
100
c
101
c\EndLib
102
c
103
c-----------------------------------------------------------------------
104
c
105
subroutine dstqrb ( n, d, e, z, work, info )
106
c
107
c %------------------%
108
c | Scalar Arguments |
109
c %------------------%
110
c
111
integer info, n
112
c
113
c %-----------------%
114
c | Array Arguments |
115
c %-----------------%
116
c
117
Double precision
118
& d( n ), e( n-1 ), z( n ), work( 2*n-2 )
119
c
120
c .. parameters ..
121
Double precision
122
& zero, one, two, three
123
parameter ( zero = 0.0D+0, one = 1.0D+0,
124
& two = 2.0D+0, three = 3.0D+0 )
125
integer maxit
126
parameter ( maxit = 30 )
127
c ..
128
c .. local scalars ..
129
integer i, icompz, ii, iscale, j, jtot, k, l, l1, lend,
130
& lendm1, lendp1, lendsv, lm1, lsv, m, mm, mm1,
131
& nm1, nmaxit
132
Double precision
133
& anorm, b, c, eps, eps2, f, g, p, r, rt1, rt2,
134
& s, safmax, safmin, ssfmax, ssfmin, tst
135
c ..
136
c .. external functions ..
137
logical lsame
138
Double precision
139
& dlamch, dlanst, dlapy2
140
external lsame, dlamch, dlanst, dlapy2
141
c ..
142
c .. external subroutines ..
143
external dlae2, dlaev2, dlartg, dlascl, dlaset, dlasr,
144
& dlasrt, dswap, xerbla
145
c ..
146
c .. intrinsic functions ..
147
intrinsic abs, max, sign, sqrt
148
c ..
149
c .. executable statements ..
150
c
151
c test the input parameters.
152
c
153
info = 0
154
c
155
c$$$ IF( LSAME( COMPZ, 'N' ) ) THEN
156
c$$$ ICOMPZ = 0
157
c$$$ ELSE IF( LSAME( COMPZ, 'V' ) ) THEN
158
c$$$ ICOMPZ = 1
159
c$$$ ELSE IF( LSAME( COMPZ, 'I' ) ) THEN
160
c$$$ ICOMPZ = 2
161
c$$$ ELSE
162
c$$$ ICOMPZ = -1
163
c$$$ END IF
164
c$$$ IF( ICOMPZ.LT.0 ) THEN
165
c$$$ INFO = -1
166
c$$$ ELSE IF( N.LT.0 ) THEN
167
c$$$ INFO = -2
168
c$$$ ELSE IF( ( LDZ.LT.1 ) .OR. ( ICOMPZ.GT.0 .AND. LDZ.LT.MAX( 1,
169
c$$$ $ N ) ) ) THEN
170
c$$$ INFO = -6
171
c$$$ END IF
172
c$$$ IF( INFO.NE.0 ) THEN
173
c$$$ CALL XERBLA( 'SSTEQR', -INFO )
174
c$$$ RETURN
175
c$$$ END IF
176
c
177
c *** New starting with version 2.5 ***
178
c
179
icompz = 2
180
c *************************************
181
c
182
c quick return if possible
183
c
184
if( n.eq.0 )
185
$ return
186
c
187
if( n.eq.1 ) then
188
if( icompz.eq.2 ) z( 1 ) = one
189
return
190
end if
191
c
192
c determine the unit roundoff and over/underflow thresholds.
193
c
194
eps = dlamch( 'e' )
195
eps2 = eps**2
196
safmin = dlamch( 's' )
197
safmax = one / safmin
198
ssfmax = sqrt( safmax ) / three
199
ssfmin = sqrt( safmin ) / eps2
200
c
201
c compute the eigenvalues and eigenvectors of the tridiagonal
202
c matrix.
203
c
204
c$$ if( icompz.eq.2 )
205
c$$$ $ call dlaset( 'full', n, n, zero, one, z, ldz )
206
c
207
c *** New starting with version 2.5 ***
208
c
209
if ( icompz .eq. 2 ) then
210
do 5 j = 1, n-1
211
z(j) = zero
212
5 continue
213
z( n ) = one
214
end if
215
c *************************************
216
c
217
nmaxit = n*maxit
218
jtot = 0
219
c
220
c determine where the matrix splits and choose ql or qr iteration
221
c for each block, according to whether top or bottom diagonal
222
c element is smaller.
223
c
224
l1 = 1
225
nm1 = n - 1
226
c
227
10 continue
228
if( l1.gt.n )
229
$ go to 160
230
if( l1.gt.1 )
231
$ e( l1-1 ) = zero
232
if( l1.le.nm1 ) then
233
do 20 m = l1, nm1
234
tst = abs( e( m ) )
235
if( tst.eq.zero )
236
$ go to 30
237
if( tst.le.( sqrt( abs( d( m ) ) )*sqrt( abs( d( m+
238
$ 1 ) ) ) )*eps ) then
239
e( m ) = zero
240
go to 30
241
end if
242
20 continue
243
end if
244
m = n
245
c
246
30 continue
247
l = l1
248
lsv = l
249
lend = m
250
lendsv = lend
251
l1 = m + 1
252
if( lend.eq.l )
253
$ go to 10
254
c
255
c scale submatrix in rows and columns l to lend
256
c
257
anorm = dlanst( 'i', lend-l+1, d( l ), e( l ) )
258
iscale = 0
259
if( anorm.eq.zero )
260
$ go to 10
261
if( anorm.gt.ssfmax ) then
262
iscale = 1
263
call dlascl( 'g', 0, 0, anorm, ssfmax, lend-l+1, 1, d( l ), n,
264
$ info )
265
call dlascl( 'g', 0, 0, anorm, ssfmax, lend-l, 1, e( l ), n,
266
$ info )
267
else if( anorm.lt.ssfmin ) then
268
iscale = 2
269
call dlascl( 'g', 0, 0, anorm, ssfmin, lend-l+1, 1, d( l ), n,
270
$ info )
271
call dlascl( 'g', 0, 0, anorm, ssfmin, lend-l, 1, e( l ), n,
272
$ info )
273
end if
274
c
275
c choose between ql and qr iteration
276
c
277
if( abs( d( lend ) ).lt.abs( d( l ) ) ) then
278
lend = lsv
279
l = lendsv
280
end if
281
c
282
if( lend.gt.l ) then
283
c
284
c ql iteration
285
c
286
c look for small subdiagonal element.
287
c
288
40 continue
289
if( l.ne.lend ) then
290
lendm1 = lend - 1
291
do 50 m = l, lendm1
292
tst = abs( e( m ) )**2
293
if( tst.le.( eps2*abs( d( m ) ) )*abs( d( m+1 ) )+
294
$ safmin )go to 60
295
50 continue
296
end if
297
c
298
m = lend
299
c
300
60 continue
301
if( m.lt.lend )
302
$ e( m ) = zero
303
p = d( l )
304
if( m.eq.l )
305
$ go to 80
306
c
307
c if remaining matrix is 2-by-2, use dlae2 or dlaev2
308
c to compute its eigensystem.
309
c
310
if( m.eq.l+1 ) then
311
if( icompz.gt.0 ) then
312
call dlaev2( d( l ), e( l ), d( l+1 ), rt1, rt2, c, s )
313
work( l ) = c
314
work( n-1+l ) = s
315
c$$$ call dlasr( 'r', 'v', 'b', n, 2, work( l ),
316
c$$$ $ work( n-1+l ), z( 1, l ), ldz )
317
c
318
c *** New starting with version 2.5 ***
319
c
320
tst = z(l+1)
321
z(l+1) = c*tst - s*z(l)
322
z(l) = s*tst + c*z(l)
323
c *************************************
324
else
325
call dlae2( d( l ), e( l ), d( l+1 ), rt1, rt2 )
326
end if
327
d( l ) = rt1
328
d( l+1 ) = rt2
329
e( l ) = zero
330
l = l + 2
331
if( l.le.lend )
332
$ go to 40
333
go to 140
334
end if
335
c
336
if( jtot.eq.nmaxit )
337
$ go to 140
338
jtot = jtot + 1
339
c
340
c form shift.
341
c
342
g = ( d( l+1 )-p ) / ( two*e( l ) )
343
r = dlapy2( g, one )
344
g = d( m ) - p + ( e( l ) / ( g+sign( r, g ) ) )
345
c
346
s = one
347
c = one
348
p = zero
349
c
350
c inner loop
351
c
352
mm1 = m - 1
353
do 70 i = mm1, l, -1
354
f = s*e( i )
355
b = c*e( i )
356
call dlartg( g, f, c, s, r )
357
if( i.ne.m-1 )
358
$ e( i+1 ) = r
359
g = d( i+1 ) - p
360
r = ( d( i )-g )*s + two*c*b
361
p = s*r
362
d( i+1 ) = g + p
363
g = c*r - b
364
c
365
c if eigenvectors are desired, then save rotations.
366
c
367
if( icompz.gt.0 ) then
368
work( i ) = c
369
work( n-1+i ) = -s
370
end if
371
c
372
70 continue
373
c
374
c if eigenvectors are desired, then apply saved rotations.
375
c
376
if( icompz.gt.0 ) then
377
mm = m - l + 1
378
c$$$ call dlasr( 'r', 'v', 'b', n, mm, work( l ), work( n-1+l ),
379
c$$$ $ z( 1, l ), ldz )
380
c
381
c *** New starting with version 2.5 ***
382
c
383
call dlasr( 'r', 'v', 'b', 1, mm, work( l ),
384
& work( n-1+l ), z( l ), 1 )
385
c *************************************
386
end if
387
c
388
d( l ) = d( l ) - p
389
e( l ) = g
390
go to 40
391
c
392
c eigenvalue found.
393
c
394
80 continue
395
d( l ) = p
396
c
397
l = l + 1
398
if( l.le.lend )
399
$ go to 40
400
go to 140
401
c
402
else
403
c
404
c qr iteration
405
c
406
c look for small superdiagonal element.
407
c
408
90 continue
409
if( l.ne.lend ) then
410
lendp1 = lend + 1
411
do 100 m = l, lendp1, -1
412
tst = abs( e( m-1 ) )**2
413
if( tst.le.( eps2*abs( d( m ) ) )*abs( d( m-1 ) )+
414
$ safmin )go to 110
415
100 continue
416
end if
417
c
418
m = lend
419
c
420
110 continue
421
if( m.gt.lend )
422
$ e( m-1 ) = zero
423
p = d( l )
424
if( m.eq.l )
425
$ go to 130
426
c
427
c if remaining matrix is 2-by-2, use dlae2 or dlaev2
428
c to compute its eigensystem.
429
c
430
if( m.eq.l-1 ) then
431
if( icompz.gt.0 ) then
432
call dlaev2( d( l-1 ), e( l-1 ), d( l ), rt1, rt2, c, s )
433
c$$$ work( m ) = c
434
c$$$ work( n-1+m ) = s
435
c$$$ call dlasr( 'r', 'v', 'f', n, 2, work( m ),
436
c$$$ $ work( n-1+m ), z( 1, l-1 ), ldz )
437
c
438
c *** New starting with version 2.5 ***
439
c
440
tst = z(l)
441
z(l) = c*tst - s*z(l-1)
442
z(l-1) = s*tst + c*z(l-1)
443
c *************************************
444
else
445
call dlae2( d( l-1 ), e( l-1 ), d( l ), rt1, rt2 )
446
end if
447
d( l-1 ) = rt1
448
d( l ) = rt2
449
e( l-1 ) = zero
450
l = l - 2
451
if( l.ge.lend )
452
$ go to 90
453
go to 140
454
end if
455
c
456
if( jtot.eq.nmaxit )
457
$ go to 140
458
jtot = jtot + 1
459
c
460
c form shift.
461
c
462
g = ( d( l-1 )-p ) / ( two*e( l-1 ) )
463
r = dlapy2( g, one )
464
g = d( m ) - p + ( e( l-1 ) / ( g+sign( r, g ) ) )
465
c
466
s = one
467
c = one
468
p = zero
469
c
470
c inner loop
471
c
472
lm1 = l - 1
473
do 120 i = m, lm1
474
f = s*e( i )
475
b = c*e( i )
476
call dlartg( g, f, c, s, r )
477
if( i.ne.m )
478
$ e( i-1 ) = r
479
g = d( i ) - p
480
r = ( d( i+1 )-g )*s + two*c*b
481
p = s*r
482
d( i ) = g + p
483
g = c*r - b
484
c
485
c if eigenvectors are desired, then save rotations.
486
c
487
if( icompz.gt.0 ) then
488
work( i ) = c
489
work( n-1+i ) = s
490
end if
491
c
492
120 continue
493
c
494
c if eigenvectors are desired, then apply saved rotations.
495
c
496
if( icompz.gt.0 ) then
497
mm = l - m + 1
498
c$$$ call dlasr( 'r', 'v', 'f', n, mm, work( m ), work( n-1+m ),
499
c$$$ $ z( 1, m ), ldz )
500
c
501
c *** New starting with version 2.5 ***
502
c
503
call dlasr( 'r', 'v', 'f', 1, mm, work( m ), work( n-1+m ),
504
& z( m ), 1 )
505
c *************************************
506
end if
507
c
508
d( l ) = d( l ) - p
509
e( lm1 ) = g
510
go to 90
511
c
512
c eigenvalue found.
513
c
514
130 continue
515
d( l ) = p
516
c
517
l = l - 1
518
if( l.ge.lend )
519
$ go to 90
520
go to 140
521
c
522
end if
523
c
524
c undo scaling if necessary
525
c
526
140 continue
527
if( iscale.eq.1 ) then
528
call dlascl( 'g', 0, 0, ssfmax, anorm, lendsv-lsv+1, 1,
529
$ d( lsv ), n, info )
530
call dlascl( 'g', 0, 0, ssfmax, anorm, lendsv-lsv, 1, e( lsv ),
531
$ n, info )
532
else if( iscale.eq.2 ) then
533
call dlascl( 'g', 0, 0, ssfmin, anorm, lendsv-lsv+1, 1,
534
$ d( lsv ), n, info )
535
call dlascl( 'g', 0, 0, ssfmin, anorm, lendsv-lsv, 1, e( lsv ),
536
$ n, info )
537
end if
538
c
539
c check for no convergence to an eigenvalue after a total
540
c of n*maxit iterations.
541
c
542
if( jtot.lt.nmaxit )
543
$ go to 10
544
do 150 i = 1, n - 1
545
if( e( i ).ne.zero )
546
$ info = info + 1
547
150 continue
548
go to 190
549
c
550
c order eigenvalues and eigenvectors.
551
c
552
160 continue
553
if( icompz.eq.0 ) then
554
c
555
c use quick sort
556
c
557
call dlasrt( 'i', n, d, info )
558
c
559
else
560
c
561
c use selection sort to minimize swaps of eigenvectors
562
c
563
do 180 ii = 2, n
564
i = ii - 1
565
k = i
566
p = d( i )
567
do 170 j = ii, n
568
if( d( j ).lt.p ) then
569
k = j
570
p = d( j )
571
end if
572
170 continue
573
if( k.ne.i ) then
574
d( k ) = d( i )
575
d( i ) = p
576
c$$$ call dswap( n, z( 1, i ), 1, z( 1, k ), 1 )
577
c *** New starting with version 2.5 ***
578
c
579
p = z(k)
580
z(k) = z(i)
581
z(i) = p
582
c *************************************
583
end if
584
180 continue
585
end if
586
c
587
190 continue
588
return
589
c
590
c %---------------%
591
c | End of dstqrb |
592
c %---------------%
593
c
594
end
595
596