158
159
160
161
162
163
164 CHARACTER UPLO
165 INTEGER INFO, LDA, N, NB
166
167
168 INTEGER IPIV( * )
169 REAL A( LDA, * ), E( * ), WORK( N+NB+1, * )
170
171
172
173
174
175 REAL ONE, ZERO
176 parameter( one = 1.0e+0, zero = 0.0e+0 )
177
178
179 LOGICAL UPPER
180 INTEGER CUT, I, ICOUNT, INVD, IP, K, NNB, J, U11
181 REAL AK, AKKP1, AKP1, D, T, U01_I_J, U01_IP1_J,
182 $ U11_I_J, U11_IP1_J
183
184
185 LOGICAL LSAME
187
188
191
192
193 INTRINSIC abs, max, mod
194
195
196
197
198
199 info = 0
200 upper =
lsame( uplo,
'U' )
201 IF( .NOT.upper .AND. .NOT.
lsame( uplo,
'L' ) )
THEN
202 info = -1
203 ELSE IF( n.LT.0 ) THEN
204 info = -2
205 ELSE IF( lda.LT.max( 1, n ) ) THEN
206 info = -4
207 END IF
208
209
210
211 IF( info.NE.0 ) THEN
212 CALL xerbla(
'SSYTRI_3X', -info )
213 RETURN
214 END IF
215 IF( n.EQ.0 )
216 $ RETURN
217
218
219
220 DO k = 1, n
221 work( k, 1 ) = e( k )
222 END DO
223
224
225
226 IF( upper ) THEN
227
228
229
230 DO info = n, 1, -1
231 IF( ipiv( info ).GT.0 .AND. a( info, info ).EQ.zero )
232 $ RETURN
233 END DO
234 ELSE
235
236
237
238 DO info = 1, n
239 IF( ipiv( info ).GT.0 .AND. a( info, info ).EQ.zero )
240 $ RETURN
241 END DO
242 END IF
243
244 info = 0
245
246
247
248
249
250
251
252 u11 = n
253
254
255
256
257 invd = nb + 2
258
259 IF( upper ) THEN
260
261
262
263
264
265 CALL strtri( uplo,
'U', n, a, lda, info )
266
267
268
269 k = 1
270 DO WHILE( k.LE.n )
271 IF( ipiv( k ).GT.0 ) THEN
272
273 work( k, invd ) = one / a( k, k )
274 work( k, invd+1 ) = zero
275 ELSE
276
277 t = work( k+1, 1 )
278 ak = a( k, k ) / t
279 akp1 = a( k+1, k+1 ) / t
280 akkp1 = work( k+1, 1 ) / t
281 d = t*( ak*akp1-one )
282 work( k, invd ) = akp1 / d
283 work( k+1, invd+1 ) = ak / d
284 work( k, invd+1 ) = -akkp1 / d
285 work( k+1, invd ) = work( k, invd+1 )
286 k = k + 1
287 END IF
288 k = k + 1
289 END DO
290
291
292
293
294
295 cut = n
296 DO WHILE( cut.GT.0 )
297 nnb = nb
298 IF( cut.LE.nnb ) THEN
299 nnb = cut
300 ELSE
301 icount = 0
302
303 DO i = cut+1-nnb, cut
304 IF( ipiv( i ).LT.0 ) icount = icount + 1
305 END DO
306
307 IF( mod( icount, 2 ).EQ.1 ) nnb = nnb + 1
308 END IF
309
310 cut = cut - nnb
311
312
313
314 DO i = 1, cut
315 DO j = 1, nnb
316 work( i, j ) = a( i, cut+j )
317 END DO
318 END DO
319
320
321
322 DO i = 1, nnb
323 work( u11+i, i ) = one
324 DO j = 1, i-1
325 work( u11+i, j ) = zero
326 END DO
327 DO j = i+1, nnb
328 work( u11+i, j ) = a( cut+i, cut+j )
329 END DO
330 END DO
331
332
333
334 i = 1
335 DO WHILE( i.LE.cut )
336 IF( ipiv( i ).GT.0 ) THEN
337 DO j = 1, nnb
338 work( i, j ) = work( i, invd ) * work( i, j )
339 END DO
340 ELSE
341 DO j = 1, nnb
342 u01_i_j = work( i, j )
343 u01_ip1_j = work( i+1, j )
344 work( i, j ) = work( i, invd ) * u01_i_j
345 $ + work( i, invd+1 ) * u01_ip1_j
346 work( i+1, j ) = work( i+1, invd ) * u01_i_j
347 $ + work( i+1, invd+1 ) * u01_ip1_j
348 END DO
349 i = i + 1
350 END IF
351 i = i + 1
352 END DO
353
354
355
356 i = 1
357 DO WHILE ( i.LE.nnb )
358 IF( ipiv( cut+i ).GT.0 ) THEN
359 DO j = i, nnb
360 work( u11+i, j ) = work(cut+i,invd) * work(u11+i,j)
361 END DO
362 ELSE
363 DO j = i, nnb
364 u11_i_j = work(u11+i,j)
365 u11_ip1_j = work(u11+i+1,j)
366 work( u11+i, j ) = work(cut+i,invd) * work(u11+i,j)
367 $ + work(cut+i,invd+1) * work(u11+i+1,j)
368 work( u11+i+1, j ) = work(cut+i+1,invd) * u11_i_j
369 $ + work(cut+i+1,invd+1) * u11_ip1_j
370 END DO
371 i = i + 1
372 END IF
373 i = i + 1
374 END DO
375
376
377
378 CALL strmm(
'L',
'U',
'T',
'U', nnb, nnb,
379 $ one, a( cut+1, cut+1 ), lda, work( u11+1, 1 ),
380 $ n+nb+1 )
381
382 DO i = 1, nnb
383 DO j = i, nnb
384 a( cut+i, cut+j ) = work( u11+i, j )
385 END DO
386 END DO
387
388
389
390 CALL sgemm(
'T',
'N', nnb, nnb, cut, one, a( 1, cut+1 ),
391 $ lda, work, n+nb+1, zero, work(u11+1,1), n+nb+1 )
392
393
394
395
396 DO i = 1, nnb
397 DO j = i, nnb
398 a( cut+i, cut+j ) = a( cut+i, cut+j ) + work(u11+i,j)
399 END DO
400 END DO
401
402
403
404 CALL strmm(
'L', uplo,
'T',
'U', cut, nnb,
405 $ one, a, lda, work, n+nb+1 )
406
407
408
409
410 DO i = 1, cut
411 DO j = 1, nnb
412 a( i, cut+j ) = work( i, j )
413 END DO
414 END DO
415
416
417
418 END DO
419
420
421
422
423
424
425
426
427
428
429
430
431 DO i = 1, n
432 ip = abs( ipiv( i ) )
433 IF( ip.NE.i ) THEN
434 IF (i .LT. ip)
CALL ssyswapr( uplo, n, a, lda, i ,
435 $ ip )
436 IF (i .GT. ip)
CALL ssyswapr( uplo, n, a, lda, ip ,
437 $ i )
438 END IF
439 END DO
440
441 ELSE
442
443
444
445
446
447 CALL strtri( uplo,
'U', n, a, lda, info )
448
449
450
451 k = n
452 DO WHILE ( k .GE. 1 )
453 IF( ipiv( k ).GT.0 ) THEN
454
455 work( k, invd ) = one / a( k, k )
456 work( k, invd+1 ) = zero
457 ELSE
458
459 t = work( k-1, 1 )
460 ak = a( k-1, k-1 ) / t
461 akp1 = a( k, k ) / t
462 akkp1 = work( k-1, 1 ) / t
463 d = t*( ak*akp1-one )
464 work( k-1, invd ) = akp1 / d
465 work( k, invd ) = ak / d
466 work( k, invd+1 ) = -akkp1 / d
467 work( k-1, invd+1 ) = work( k, invd+1 )
468 k = k - 1
469 END IF
470 k = k - 1
471 END DO
472
473
474
475
476
477 cut = 0
478 DO WHILE( cut.LT.n )
479 nnb = nb
480 IF( (cut + nnb).GT.n ) THEN
481 nnb = n - cut
482 ELSE
483 icount = 0
484
485 DO i = cut + 1, cut+nnb
486 IF ( ipiv( i ).LT.0 ) icount = icount + 1
487 END DO
488
489 IF( mod( icount, 2 ).EQ.1 ) nnb = nnb + 1
490 END IF
491
492
493
494 DO i = 1, n-cut-nnb
495 DO j = 1, nnb
496 work( i, j ) = a( cut+nnb+i, cut+j )
497 END DO
498 END DO
499
500
501
502 DO i = 1, nnb
503 work( u11+i, i) = one
504 DO j = i+1, nnb
505 work( u11+i, j ) = zero
506 END DO
507 DO j = 1, i-1
508 work( u11+i, j ) = a( cut+i, cut+j )
509 END DO
510 END DO
511
512
513
514 i = n-cut-nnb
515 DO WHILE( i.GE.1 )
516 IF( ipiv( cut+nnb+i ).GT.0 ) THEN
517 DO j = 1, nnb
518 work( i, j ) = work( cut+nnb+i, invd) * work( i, j)
519 END DO
520 ELSE
521 DO j = 1, nnb
522 u01_i_j = work(i,j)
523 u01_ip1_j = work(i-1,j)
524 work(i,j)=work(cut+nnb+i,invd)*u01_i_j+
525 $ work(cut+nnb+i,invd+1)*u01_ip1_j
526 work(i-1,j)=work(cut+nnb+i-1,invd+1)*u01_i_j+
527 $ work(cut+nnb+i-1,invd)*u01_ip1_j
528 END DO
529 i = i - 1
530 END IF
531 i = i - 1
532 END DO
533
534
535
536 i = nnb
537 DO WHILE( i.GE.1 )
538 IF( ipiv( cut+i ).GT.0 ) THEN
539 DO j = 1, nnb
540 work( u11+i, j ) = work( cut+i, invd)*work(u11+i,j)
541 END DO
542
543 ELSE
544 DO j = 1, nnb
545 u11_i_j = work( u11+i, j )
546 u11_ip1_j = work( u11+i-1, j )
547 work( u11+i, j ) = work(cut+i,invd) * work(u11+i,j)
548 $ + work(cut+i,invd+1) * u11_ip1_j
549 work( u11+i-1, j ) = work(cut+i-1,invd+1) * u11_i_j
550 $ + work(cut+i-1,invd) * u11_ip1_j
551 END DO
552 i = i - 1
553 END IF
554 i = i - 1
555 END DO
556
557
558
559 CALL strmm(
'L', uplo,
'T',
'U', nnb, nnb, one,
560 $ a( cut+1, cut+1 ), lda, work( u11+1, 1 ),
561 $ n+nb+1 )
562
563
564 DO i = 1, nnb
565 DO j = 1, i
566 a( cut+i, cut+j ) = work( u11+i, j )
567 END DO
568 END DO
569
570 IF( (cut+nnb).LT.n ) THEN
571
572
573
574 CALL sgemm(
'T',
'N', nnb, nnb, n-nnb-cut, one,
575 $ a( cut+nnb+1, cut+1 ), lda, work, n+nb+1,
576 $ zero, work( u11+1, 1 ), n+nb+1 )
577
578
579
580
581 DO i = 1, nnb
582 DO j = 1, i
583 a( cut+i, cut+j ) = a( cut+i, cut+j )+work(u11+i,j)
584 END DO
585 END DO
586
587
588
589 CALL strmm(
'L', uplo,
'T',
'U', n-nnb-cut, nnb, one,
590 $ a( cut+nnb+1, cut+nnb+1 ), lda, work,
591 $ n+nb+1 )
592
593
594
595 DO i = 1, n-cut-nnb
596 DO j = 1, nnb
597 a( cut+nnb+i, cut+j ) = work( i, j )
598 END DO
599 END DO
600
601 ELSE
602
603
604
605 DO i = 1, nnb
606 DO j = 1, i
607 a( cut+i, cut+j ) = work( u11+i, j )
608 END DO
609 END DO
610 END IF
611
612
613
614 cut = cut + nnb
615
616 END DO
617
618
619
620
621
622
623
624
625
626
627
628
629 DO i = n, 1, -1
630 ip = abs( ipiv( i ) )
631 IF( ip.NE.i ) THEN
632 IF (i .LT. ip)
CALL ssyswapr( uplo, n, a, lda, i ,
633 $ ip )
634 IF (i .GT. ip)
CALL ssyswapr( uplo, n, a, lda, ip ,
635 $ i )
636 END IF
637 END DO
638
639 END IF
640
641 RETURN
642
643
644
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 strmm(side, uplo, transa, diag, m, n, alpha, a, lda, b, ldb)
STRMM
subroutine strtri(uplo, diag, n, a, lda, info)
STRTRI