118
119
120
121
122
123
124 CHARACTER UPLO
125 INTEGER INFO, LDA, N, NB
126
127
128 INTEGER IPIV( * )
129 REAL A( LDA, * ), WORK( N+NB+1,* )
130
131
132
133
134
135 REAL ONE, ZERO
136 parameter( one = 1.0e+0, zero = 0.0e+0 )
137
138
139 LOGICAL UPPER
140 INTEGER I, IINFO, IP, K, CUT, NNB
141 INTEGER COUNT
142 INTEGER J, U11, INVD
143
144 REAL AK, AKKP1, AKP1, D, T
145 REAL U01_I_J, U01_IP1_J
146 REAL U11_I_J, U11_IP1_J
147
148
149 LOGICAL LSAME
151
152
155
156
157 INTRINSIC max
158
159
160
161
162
163 info = 0
164 upper =
lsame( uplo,
'U' )
165 IF( .NOT.upper .AND. .NOT.
lsame( uplo,
'L' ) )
THEN
166 info = -1
167 ELSE IF( n.LT.0 ) THEN
168 info = -2
169 ELSE IF( lda.LT.max( 1, n ) ) THEN
170 info = -4
171 END IF
172
173
174
175
176 IF( info.NE.0 ) THEN
177 CALL xerbla(
'SSYTRI2X', -info )
178 RETURN
179 END IF
180 IF( n.EQ.0 )
181 $ RETURN
182
183
184
185
186 CALL ssyconv( uplo,
'C', n, a, lda, ipiv, work, iinfo )
187
188
189
190 IF( upper ) THEN
191
192
193
194 DO info = n, 1, -1
195 IF( ipiv( info ).GT.0 .AND. a( info, info ).EQ.zero )
196 $ RETURN
197 END DO
198 ELSE
199
200
201
202 DO info = 1, n
203 IF( ipiv( info ).GT.0 .AND. a( info, info ).EQ.zero )
204 $ RETURN
205 END DO
206 END IF
207 info = 0
208
209
210
211
212
213
214 u11 = n
215
216
217 invd = nb+2
218
219 IF( upper ) THEN
220
221
222
223 CALL strtri( uplo,
'U', n, a, lda, info )
224
225
226
227 k=1
228 DO WHILE ( k .LE. n )
229 IF( ipiv( k ).GT.0 ) THEN
230
231 work(k,invd) = one / a( k, k )
232 work(k,invd+1) = 0
233 k=k+1
234 ELSE
235
236 t = work(k+1,1)
237 ak = a( k, k ) / t
238 akp1 = a( k+1, k+1 ) / t
239 akkp1 = work(k+1,1) / t
240 d = t*( ak*akp1-one )
241 work(k,invd) = akp1 / d
242 work(k+1,invd+1) = ak / d
243 work(k,invd+1) = -akkp1 / d
244 work(k+1,invd) = -akkp1 / d
245 k=k+2
246 END IF
247 END DO
248
249
250
251
252
253 cut=n
254 DO WHILE (cut .GT. 0)
255 nnb=nb
256 IF (cut .LE. nnb) THEN
257 nnb=cut
258 ELSE
259 count = 0
260
261 DO i=cut+1-nnb,cut
262 IF (ipiv(i) .LT. 0) count=count+1
263 END DO
264
265 IF (mod(count,2) .EQ. 1) nnb=nnb+1
266 END IF
267
268 cut=cut-nnb
269
270
271
272 DO i=1,cut
273 DO j=1,nnb
274 work(i,j)=a(i,cut+j)
275 END DO
276 END DO
277
278
279
280 DO i=1,nnb
281 work(u11+i,i)=one
282 DO j=1,i-1
283 work(u11+i,j)=zero
284 END DO
285 DO j=i+1,nnb
286 work(u11+i,j)=a(cut+i,cut+j)
287 END DO
288 END DO
289
290
291
292 i=1
293 DO WHILE (i .LE. cut)
294 IF (ipiv(i) > 0) THEN
295 DO j=1,nnb
296 work(i,j)=work(i,invd)*work(i,j)
297 END DO
298 i=i+1
299 ELSE
300 DO j=1,nnb
301 u01_i_j = work(i,j)
302 u01_ip1_j = work(i+1,j)
303 work(i,j)=work(i,invd)*u01_i_j+
304 $ work(i,invd+1)*u01_ip1_j
305 work(i+1,j)=work(i+1,invd)*u01_i_j+
306 $ work(i+1,invd+1)*u01_ip1_j
307 END DO
308 i=i+2
309 END IF
310 END DO
311
312
313
314 i=1
315 DO WHILE (i .LE. nnb)
316 IF (ipiv(cut+i) > 0) THEN
317 DO j=i,nnb
318 work(u11+i,j)=work(cut+i,invd)*work(u11+i,j)
319 END DO
320 i=i+1
321 ELSE
322 DO j=i,nnb
323 u11_i_j = work(u11+i,j)
324 u11_ip1_j = work(u11+i+1,j)
325 work(u11+i,j)=work(cut+i,invd)*work(u11+i,j) +
326 $ work(cut+i,invd+1)*work(u11+i+1,j)
327 work(u11+i+1,j)=work(cut+i+1,invd)*u11_i_j+
328 $ work(cut+i+1,invd+1)*u11_ip1_j
329 END DO
330 i=i+2
331 END IF
332 END DO
333
334
335
336 CALL strmm(
'L',
'U',
'T',
'U',nnb, nnb,
337 $ one,a(cut+1,cut+1),lda,work(u11+1,1),n+nb+1)
338
339 DO i=1,nnb
340 DO j=i,nnb
341 a(cut+i,cut+j)=work(u11+i,j)
342 END DO
343 END DO
344
345
346
347 CALL sgemm(
'T',
'N',nnb,nnb,cut,one,a(1,cut+1),lda,
348 $ work,n+nb+1, zero, work(u11+1,1), n+nb+1)
349
350
351
352 DO i=1,nnb
353 DO j=i,nnb
354 a(cut+i,cut+j)=a(cut+i,cut+j)+work(u11+i,j)
355 END DO
356 END DO
357
358
359
360 CALL strmm(
'L',uplo,
'T',
'U',cut, nnb,
361 $ one,a,lda,work,n+nb+1)
362
363
364
365
366 DO i=1,cut
367 DO j=1,nnb
368 a(i,cut+j)=work(i,j)
369 END DO
370 END DO
371
372
373
374 END DO
375
376
377
378 i=1
379 DO WHILE ( i .LE. n )
380 IF( ipiv(i) .GT. 0 ) THEN
381 ip=ipiv(i)
382 IF (i .LT. ip)
CALL ssyswapr( uplo, n, a, lda, i ,
383 $ ip )
384 IF (i .GT. ip)
CALL ssyswapr( uplo, n, a, lda, ip ,
385 $ i )
386 ELSE
387 ip=-ipiv(i)
388 i=i+1
389 IF ( (i-1) .LT. ip)
390 $
CALL ssyswapr( uplo, n, a, lda, i-1 ,ip )
391 IF ( (i-1) .GT. ip)
392 $
CALL ssyswapr( uplo, n, a, lda, ip ,i-1 )
393 ENDIF
394 i=i+1
395 END DO
396 ELSE
397
398
399
400
401
402 CALL strtri( uplo,
'U', n, a, lda, info )
403
404
405
406 k=n
407 DO WHILE ( k .GE. 1 )
408 IF( ipiv( k ).GT.0 ) THEN
409
410 work(k,invd) = one / a( k, k )
411 work(k,invd+1) = 0
412 k=k-1
413 ELSE
414
415 t = work(k-1,1)
416 ak = a( k-1, k-1 ) / t
417 akp1 = a( k, k ) / t
418 akkp1 = work(k-1,1) / t
419 d = t*( ak*akp1-one )
420 work(k-1,invd) = akp1 / d
421 work(k,invd) = ak / d
422 work(k,invd+1) = -akkp1 / d
423 work(k-1,invd+1) = -akkp1 / d
424 k=k-2
425 END IF
426 END DO
427
428
429
430
431
432 cut=0
433 DO WHILE (cut .LT. n)
434 nnb=nb
435 IF (cut + nnb .GT. n) THEN
436 nnb=n-cut
437 ELSE
438 count = 0
439
440 DO i=cut+1,cut+nnb
441 IF (ipiv(i) .LT. 0) count=count+1
442 END DO
443
444 IF (mod(count,2) .EQ. 1) nnb=nnb+1
445 END IF
446
447 DO i=1,n-cut-nnb
448 DO j=1,nnb
449 work(i,j)=a(cut+nnb+i,cut+j)
450 END DO
451 END DO
452
453 DO i=1,nnb
454 work(u11+i,i)=one
455 DO j=i+1,nnb
456 work(u11+i,j)=zero
457 END DO
458 DO j=1,i-1
459 work(u11+i,j)=a(cut+i,cut+j)
460 END DO
461 END DO
462
463
464
465 i=n-cut-nnb
466 DO WHILE (i .GE. 1)
467 IF (ipiv(cut+nnb+i) > 0) THEN
468 DO j=1,nnb
469 work(i,j)=work(cut+nnb+i,invd)*work(i,j)
470 END DO
471 i=i-1
472 ELSE
473 DO j=1,nnb
474 u01_i_j = work(i,j)
475 u01_ip1_j = work(i-1,j)
476 work(i,j)=work(cut+nnb+i,invd)*u01_i_j+
477 $ work(cut+nnb+i,invd+1)*u01_ip1_j
478 work(i-1,j)=work(cut+nnb+i-1,invd+1)*u01_i_j+
479 $ work(cut+nnb+i-1,invd)*u01_ip1_j
480 END DO
481 i=i-2
482 END IF
483 END DO
484
485
486
487 i=nnb
488 DO WHILE (i .GE. 1)
489 IF (ipiv(cut+i) > 0) THEN
490 DO j=1,nnb
491 work(u11+i,j)=work(cut+i,invd)*work(u11+i,j)
492 END DO
493 i=i-1
494 ELSE
495 DO j=1,nnb
496 u11_i_j = work(u11+i,j)
497 u11_ip1_j = work(u11+i-1,j)
498 work(u11+i,j)=work(cut+i,invd)*work(u11+i,j) +
499 $ work(cut+i,invd+1)*u11_ip1_j
500 work(u11+i-1,j)=work(cut+i-1,invd+1)*u11_i_j+
501 $ work(cut+i-1,invd)*u11_ip1_j
502 END DO
503 i=i-2
504 END IF
505 END DO
506
507
508
509 CALL strmm(
'L',uplo,
'T',
'U',nnb, nnb,
510 $ one,a(cut+1,cut+1),lda,work(u11+1,1),n+nb+1)
511
512
513 DO i=1,nnb
514 DO j=1,i
515 a(cut+i,cut+j)=work(u11+i,j)
516 END DO
517 END DO
518
519 IF ( (cut+nnb) .LT. n ) THEN
520
521
522
523 CALL sgemm(
'T',
'N',nnb,nnb,n-nnb-cut,one,a(cut+nnb+1,cut+1)
524 $ ,lda,work,n+nb+1, zero, work(u11+1,1), n+nb+1)
525
526
527
528
529 DO i=1,nnb
530 DO j=1,i
531 a(cut+i,cut+j)=a(cut+i,cut+j)+work(u11+i,j)
532 END DO
533 END DO
534
535
536
537 CALL strmm(
'L',uplo,
'T',
'U', n-nnb-cut, nnb,
538 $ one,a(cut+nnb+1,cut+nnb+1),lda,work,n+nb+1)
539
540
541
542 DO i=1,n-cut-nnb
543 DO j=1,nnb
544 a(cut+nnb+i,cut+j)=work(i,j)
545 END DO
546 END DO
547
548 ELSE
549
550
551
552 DO i=1,nnb
553 DO j=1,i
554 a(cut+i,cut+j)=work(u11+i,j)
555 END DO
556 END DO
557 END IF
558
559
560
561 cut=cut+nnb
562 END DO
563
564
565
566 i=n
567 DO WHILE ( i .GE. 1 )
568 IF( ipiv(i) .GT. 0 ) THEN
569 ip=ipiv(i)
570 IF (i .LT. ip)
CALL ssyswapr( uplo, n, a, lda, i ,
571 $ ip )
572 IF (i .GT. ip)
CALL ssyswapr( uplo, n, a, lda, ip ,
573 $ i )
574 ELSE
575 ip=-ipiv(i)
576 IF ( i .LT. ip)
CALL ssyswapr( uplo, n, a, lda, i ,
577 $ ip )
578 IF ( i .GT. ip)
CALL ssyswapr( uplo, n, a, lda, ip ,
579 $ i )
580 i=i-1
581 ENDIF
582 i=i-1
583 END DO
584 END IF
585
586 RETURN
587
588
589
subroutine xerbla(srname, info)
subroutine sgemm(transa, transb, m, n, k, alpha, a, lda, b, ldb, beta, c, ldc)
SGEMM
subroutine ssyswapr(uplo, n, a, lda, i1, i2)
SSYSWAPR applies an elementary permutation on the rows and columns of a symmetric matrix.
logical function lsame(ca, cb)
LSAME
subroutine ssyconv(uplo, way, n, a, lda, ipiv, e, info)
SSYCONV
subroutine strmm(side, uplo, transa, diag, m, n, alpha, a, lda, b, ldb)
STRMM
subroutine strtri(uplo, diag, n, a, lda, info)
STRTRI