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