159
160
161
162
163
164
165 CHARACTER UPLO
166 INTEGER INFO, LDA, N, NB
167
168
169 INTEGER IPIV( * )
170 COMPLEX A( LDA, * ), E( * ), WORK( N+NB+1, * )
171
172
173
174
175
176 COMPLEX CONE, CZERO
177 parameter( cone = ( 1.0e+0, 0.0e+0 ),
178 $ czero = ( 0.0e+0, 0.0e+0 ) )
179
180
181 LOGICAL UPPER
182 INTEGER CUT, I, ICOUNT, INVD, IP, K, NNB, J, U11
183 COMPLEX AK, AKKP1, AKP1, D, T, U01_I_J, U01_IP1_J,
184 $ U11_I_J, U11_IP1_J
185
186
187 LOGICAL LSAME
189
190
192
193
194 INTRINSIC abs, max, mod
195
196
197
198
199
200 info = 0
201 upper =
lsame( uplo,
'U' )
202 IF( .NOT.upper .AND. .NOT.
lsame( uplo,
'L' ) )
THEN
203 info = -1
204 ELSE IF( n.LT.0 ) THEN
205 info = -2
206 ELSE IF( lda.LT.max( 1, n ) ) THEN
207 info = -4
208 END IF
209
210
211
212 IF( info.NE.0 ) THEN
213 CALL xerbla(
'CSYTRI_3X', -info )
214 RETURN
215 END IF
216 IF( n.EQ.0 )
217 $ RETURN
218
219
220
221 DO k = 1, n
222 work( k, 1 ) = e( k )
223 END DO
224
225
226
227 IF( upper ) THEN
228
229
230
231 DO info = n, 1, -1
232 IF( ipiv( info ).GT.0 .AND. a( info, info ).EQ.czero )
233 $ RETURN
234 END DO
235 ELSE
236
237
238
239 DO info = 1, n
240 IF( ipiv( info ).GT.0 .AND. a( info, info ).EQ.czero )
241 $ RETURN
242 END DO
243 END IF
244
245 info = 0
246
247
248
249
250
251
252
253 u11 = n
254
255
256
257
258 invd = nb + 2
259
260 IF( upper ) THEN
261
262
263
264
265
266 CALL ctrtri( uplo,
'U', n, a, lda, info )
267
268
269
270 k = 1
271 DO WHILE( k.LE.n )
272 IF( ipiv( k ).GT.0 ) THEN
273
274 work( k, invd ) = cone / a( k, k )
275 work( k, invd+1 ) = czero
276 ELSE
277
278 t = work( k+1, 1 )
279 ak = a( k, k ) / t
280 akp1 = a( k+1, k+1 ) / t
281 akkp1 = work( k+1, 1 ) / t
282 d = t*( ak*akp1-cone )
283 work( k, invd ) = akp1 / d
284 work( k+1, invd+1 ) = ak / d
285 work( k, invd+1 ) = -akkp1 / d
286 work( k+1, invd ) = work( k, invd+1 )
287 k = k + 1
288 END IF
289 k = k + 1
290 END DO
291
292
293
294
295
296 cut = n
297 DO WHILE( cut.GT.0 )
298 nnb = nb
299 IF( cut.LE.nnb ) THEN
300 nnb = cut
301 ELSE
302 icount = 0
303
304 DO i = cut+1-nnb, cut
305 IF( ipiv( i ).LT.0 ) icount = icount + 1
306 END DO
307
308 IF( mod( icount, 2 ).EQ.1 ) nnb = nnb + 1
309 END IF
310
311 cut = cut - nnb
312
313
314
315 DO i = 1, cut
316 DO j = 1, nnb
317 work( i, j ) = a( i, cut+j )
318 END DO
319 END DO
320
321
322
323 DO i = 1, nnb
324 work( u11+i, i ) = cone
325 DO j = 1, i-1
326 work( u11+i, j ) = czero
327 END DO
328 DO j = i+1, nnb
329 work( u11+i, j ) = a( cut+i, cut+j )
330 END DO
331 END DO
332
333
334
335 i = 1
336 DO WHILE( i.LE.cut )
337 IF( ipiv( i ).GT.0 ) THEN
338 DO j = 1, nnb
339 work( i, j ) = work( i, invd ) * work( i, j )
340 END DO
341 ELSE
342 DO j = 1, nnb
343 u01_i_j = work( i, j )
344 u01_ip1_j = work( i+1, j )
345 work( i, j ) = work( i, invd ) * u01_i_j
346 $ + work( i, invd+1 ) * u01_ip1_j
347 work( i+1, j ) = work( i+1, invd ) * u01_i_j
348 $ + work( i+1, invd+1 ) * u01_ip1_j
349 END DO
350 i = i + 1
351 END IF
352 i = i + 1
353 END DO
354
355
356
357 i = 1
358 DO WHILE ( i.LE.nnb )
359 IF( ipiv( cut+i ).GT.0 ) THEN
360 DO j = i, nnb
361 work( u11+i, j ) = work(cut+i,invd) * work(u11+i,j)
362 END DO
363 ELSE
364 DO j = i, nnb
365 u11_i_j = work(u11+i,j)
366 u11_ip1_j = work(u11+i+1,j)
367 work( u11+i, j ) = work(cut+i,invd) * work(u11+i,j)
368 $ + work(cut+i,invd+1) * work(u11+i+1,j)
369 work( u11+i+1, j ) = work(cut+i+1,invd) * u11_i_j
370 $ + work(cut+i+1,invd+1) * u11_ip1_j
371 END DO
372 i = i + 1
373 END IF
374 i = i + 1
375 END DO
376
377
378
379 CALL ctrmm(
'L',
'U',
'T',
'U', nnb, nnb,
380 $ cone, a( cut+1, cut+1 ), lda, work( u11+1, 1 ),
381 $ n+nb+1 )
382
383 DO i = 1, nnb
384 DO j = i, nnb
385 a( cut+i, cut+j ) = work( u11+i, j )
386 END DO
387 END DO
388
389
390
391 CALL cgemm(
'T',
'N', nnb, nnb, cut, cone, a( 1, cut+1 ),
392 $ lda, work, n+nb+1, czero, work(u11+1,1),
393 $ n+nb+1 )
394
395
396
397
398 DO i = 1, nnb
399 DO j = i, nnb
400 a( cut+i, cut+j ) = a( cut+i, cut+j ) + work(u11+i,j)
401 END DO
402 END DO
403
404
405
406 CALL ctrmm(
'L', uplo,
'T',
'U', cut, nnb,
407 $ cone, a, lda, work, n+nb+1 )
408
409
410
411
412 DO i = 1, cut
413 DO j = 1, nnb
414 a( i, cut+j ) = work( i, j )
415 END DO
416 END DO
417
418
419
420 END DO
421
422
423
424
425
426
427
428
429
430
431
432
433 DO i = 1, n
434 ip = abs( ipiv( i ) )
435 IF( ip.NE.i ) THEN
436 IF (i .LT. ip)
CALL csyswapr( uplo, n, a, lda, i ,ip )
437 IF (i .GT. ip)
CALL csyswapr( uplo, n, a, lda, ip ,i )
438 END IF
439 END DO
440
441 ELSE
442
443
444
445
446
447 CALL ctrtri( 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 ) = cone / a( k, k )
456 work( k, invd+1 ) = czero
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-cone )
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) = cone
504 DO j = i+1, nnb
505 work( u11+i, j ) = czero
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 ctrmm(
'L', uplo,
'T',
'U', nnb, nnb, cone,
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 cgemm(
'T',
'N', nnb, nnb, n-nnb-cut, cone,
575 $ a( cut+nnb+1, cut+1 ), lda, work, n+nb+1,
576 $ czero, 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 ctrmm(
'L', uplo,
'T',
'U', n-nnb-cut, nnb, cone,
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 csyswapr( uplo, n, a, lda, i ,ip )
633 IF (i .GT. ip)
CALL csyswapr( uplo, n, a, lda, ip ,i )
634 END IF
635 END DO
636
637 END IF
638
639 RETURN
640
641
642
subroutine xerbla(srname, info)
subroutine cgemm(transa, transb, m, n, k, alpha, a, lda, b, ldb, beta, c, ldc)
CGEMM
subroutine csyswapr(uplo, n, a, lda, i1, i2)
CSYSWAPR
logical function lsame(ca, cb)
LSAME
subroutine ctrmm(side, uplo, transa, diag, m, n, alpha, a, lda, b, ldb)
CTRMM
subroutine ctrtri(uplo, diag, n, a, lda, info)
CTRTRI