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