LAPACK 3.12.1
LAPACK: Linear Algebra PACKage
Loading...
Searching...
No Matches
csytri2x.f
Go to the documentation of this file.
1*> \brief \b CSYTRI2X
2*
3* =========== DOCUMENTATION ===========
4*
5* Online html documentation available at
6* http://www.netlib.org/lapack/explore-html/
7*
8*> Download CSYTRI2X + dependencies
9*> <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/csytri2x.f">
10*> [TGZ]</a>
11*> <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/csytri2x.f">
12*> [ZIP]</a>
13*> <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/csytri2x.f">
14*> [TXT]</a>
15*
16* Definition:
17* ===========
18*
19* SUBROUTINE CSYTRI2X( UPLO, N, A, LDA, IPIV, WORK, NB, INFO )
20*
21* .. Scalar Arguments ..
22* CHARACTER UPLO
23* INTEGER INFO, LDA, N, NB
24* ..
25* .. Array Arguments ..
26* INTEGER IPIV( * )
27* COMPLEX A( LDA, * ), WORK( N+NB+1,* )
28* ..
29*
30*
31*> \par Purpose:
32* =============
33*>
34*> \verbatim
35*>
36*> CSYTRI2X computes the inverse of a real symmetric indefinite matrix
37*> A using the factorization A = U*D*U**T or A = L*D*L**T computed by
38*> CSYTRF.
39*> \endverbatim
40*
41* Arguments:
42* ==========
43*
44*> \param[in] UPLO
45*> \verbatim
46*> UPLO is CHARACTER*1
47*> Specifies whether the details of the factorization are stored
48*> as an upper or lower triangular matrix.
49*> = 'U': Upper triangular, form is A = U*D*U**T;
50*> = 'L': Lower triangular, form is A = L*D*L**T.
51*> \endverbatim
52*>
53*> \param[in] N
54*> \verbatim
55*> N is INTEGER
56*> The order of the matrix A. N >= 0.
57*> \endverbatim
58*>
59*> \param[in,out] A
60*> \verbatim
61*> A is COMPLEX array, dimension (LDA,N)
62*> On entry, the NNB diagonal matrix D and the multipliers
63*> used to obtain the factor U or L as computed by CSYTRF.
64*>
65*> On exit, if INFO = 0, the (symmetric) inverse of the original
66*> matrix. If UPLO = 'U', the upper triangular part of the
67*> inverse is formed and the part of A below the diagonal is not
68*> referenced; if UPLO = 'L' the lower triangular part of the
69*> inverse is formed and the part of A above the diagonal is
70*> not referenced.
71*> \endverbatim
72*>
73*> \param[in] LDA
74*> \verbatim
75*> LDA is INTEGER
76*> The leading dimension of the array A. LDA >= max(1,N).
77*> \endverbatim
78*>
79*> \param[in] IPIV
80*> \verbatim
81*> IPIV is INTEGER array, dimension (N)
82*> Details of the interchanges and the NNB structure of D
83*> as determined by CSYTRF.
84*> \endverbatim
85*>
86*> \param[out] WORK
87*> \verbatim
88*> WORK is COMPLEX array, dimension (N+NB+1,NB+3)
89*> \endverbatim
90*>
91*> \param[in] NB
92*> \verbatim
93*> NB is INTEGER
94*> Block size
95*> \endverbatim
96*>
97*> \param[out] INFO
98*> \verbatim
99*> INFO is INTEGER
100*> = 0: successful exit
101*> < 0: if INFO = -i, the i-th argument had an illegal value
102*> > 0: if INFO = i, D(i,i) = 0; the matrix is singular and its
103*> inverse could not be computed.
104*> \endverbatim
105*
106* Authors:
107* ========
108*
109*> \author Univ. of Tennessee
110*> \author Univ. of California Berkeley
111*> \author Univ. of Colorado Denver
112*> \author NAG Ltd.
113*
114*> \ingroup hetri2x
115*
116* =====================================================================
117 SUBROUTINE csytri2x( UPLO, N, A, LDA, IPIV, WORK, NB, INFO )
118*
119* -- LAPACK computational routine --
120* -- LAPACK is a software package provided by Univ. of Tennessee, --
121* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
122*
123* .. Scalar Arguments ..
124 CHARACTER UPLO
125 INTEGER INFO, LDA, N, NB
126* ..
127* .. Array Arguments ..
128 INTEGER IPIV( * )
129 COMPLEX A( LDA, * ), WORK( N+NB+1,* )
130* ..
131*
132* =====================================================================
133*
134* .. Parameters ..
135 COMPLEX ONE, ZERO
136 parameter( one = ( 1.0e+0, 0.0e+0 ),
137 $ zero = ( 0.0e+0, 0.0e+0 ) )
138* ..
139* .. Local Scalars ..
140 LOGICAL UPPER
141 INTEGER I, IINFO, IP, K, CUT, NNB
142 INTEGER COUNT
143 INTEGER J, U11, INVD
144
145 COMPLEX AK, AKKP1, AKP1, D, T
146 COMPLEX U01_I_J, U01_IP1_J
147 COMPLEX U11_I_J, U11_IP1_J
148* ..
149* .. External Functions ..
150 LOGICAL LSAME
151 EXTERNAL lsame
152* ..
153* .. External Subroutines ..
154 EXTERNAL csyconv, xerbla, ctrtri
155 EXTERNAL cgemm, ctrmm, csyswapr
156* ..
157* .. Intrinsic Functions ..
158 INTRINSIC max
159* ..
160* .. Executable Statements ..
161*
162* Test the input parameters.
163*
164 info = 0
165 upper = lsame( uplo, 'U' )
166 IF( .NOT.upper .AND. .NOT.lsame( uplo, 'L' ) ) THEN
167 info = -1
168 ELSE IF( n.LT.0 ) THEN
169 info = -2
170 ELSE IF( lda.LT.max( 1, n ) ) THEN
171 info = -4
172 END IF
173*
174* Quick return if possible
175*
176*
177 IF( info.NE.0 ) THEN
178 CALL xerbla( 'CSYTRI2X', -info )
179 RETURN
180 END IF
181 IF( n.EQ.0 )
182 $ RETURN
183*
184* Convert A
185* Workspace got Non-diag elements of D
186*
187 CALL csyconv( uplo, 'C', n, a, lda, ipiv, work, iinfo )
188*
189* Check that the diagonal matrix D is nonsingular.
190*
191 IF( upper ) THEN
192*
193* Upper triangular storage: examine D from bottom to top
194*
195 DO info = n, 1, -1
196 IF( ipiv( info ).GT.0 .AND. a( info, info ).EQ.zero )
197 $ RETURN
198 END DO
199 ELSE
200*
201* Lower triangular storage: examine D from top to bottom.
202*
203 DO info = 1, n
204 IF( ipiv( info ).GT.0 .AND. a( info, info ).EQ.zero )
205 $ RETURN
206 END DO
207 END IF
208 info = 0
209*
210* Splitting Workspace
211* U01 is a block (N,NB+1)
212* The first element of U01 is in WORK(1,1)
213* U11 is a block (NB+1,NB+1)
214* The first element of U11 is in WORK(N+1,1)
215 u11 = n
216* INVD is a block (N,2)
217* The first element of INVD is in WORK(1,INVD)
218 invd = nb+2
219
220 IF( upper ) THEN
221*
222* invA = P * inv(U**T)*inv(D)*inv(U)*P**T.
223*
224 CALL ctrtri( uplo, 'U', n, a, lda, info )
225*
226* inv(D) and inv(D)*inv(U)
227*
228 k=1
229 DO WHILE ( k .LE. n )
230 IF( ipiv( k ).GT.0 ) THEN
231* 1 x 1 diagonal NNB
232 work(k,invd) = one / a( k, k )
233 work(k,invd+1) = 0
234 k=k+1
235 ELSE
236* 2 x 2 diagonal NNB
237 t = work(k+1,1)
238 ak = a( k, k ) / t
239 akp1 = a( k+1, k+1 ) / t
240 akkp1 = work(k+1,1) / t
241 d = t*( ak*akp1-one )
242 work(k,invd) = akp1 / d
243 work(k+1,invd+1) = ak / d
244 work(k,invd+1) = -akkp1 / d
245 work(k+1,invd) = -akkp1 / d
246 k=k+2
247 END IF
248 END DO
249*
250* inv(U**T) = (inv(U))**T
251*
252* inv(U**T)*inv(D)*inv(U)
253*
254 cut=n
255 DO WHILE (cut .GT. 0)
256 nnb=nb
257 IF (cut .LE. nnb) THEN
258 nnb=cut
259 ELSE
260 count = 0
261* count negative elements,
262 DO i=cut+1-nnb,cut
263 IF (ipiv(i) .LT. 0) count=count+1
264 END DO
265* need a even number for a clear cut
266 IF (mod(count,2) .EQ. 1) nnb=nnb+1
267 END IF
268
269 cut=cut-nnb
270*
271* U01 Block
272*
273 DO i=1,cut
274 DO j=1,nnb
275 work(i,j)=a(i,cut+j)
276 END DO
277 END DO
278*
279* U11 Block
280*
281 DO i=1,nnb
282 work(u11+i,i)=one
283 DO j=1,i-1
284 work(u11+i,j)=zero
285 END DO
286 DO j=i+1,nnb
287 work(u11+i,j)=a(cut+i,cut+j)
288 END DO
289 END DO
290*
291* invD*U01
292*
293 i=1
294 DO WHILE (i .LE. cut)
295 IF (ipiv(i) > 0) THEN
296 DO j=1,nnb
297 work(i,j)=work(i,invd)*work(i,j)
298 END DO
299 i=i+1
300 ELSE
301 DO j=1,nnb
302 u01_i_j = work(i,j)
303 u01_ip1_j = work(i+1,j)
304 work(i,j)=work(i,invd)*u01_i_j+
305 $ work(i,invd+1)*u01_ip1_j
306 work(i+1,j)=work(i+1,invd)*u01_i_j+
307 $ work(i+1,invd+1)*u01_ip1_j
308 END DO
309 i=i+2
310 END IF
311 END DO
312*
313* invD1*U11
314*
315 i=1
316 DO WHILE (i .LE. nnb)
317 IF (ipiv(cut+i) > 0) THEN
318 DO j=i,nnb
319 work(u11+i,j)=work(cut+i,invd)*work(u11+i,j)
320 END DO
321 i=i+1
322 ELSE
323 DO j=i,nnb
324 u11_i_j = work(u11+i,j)
325 u11_ip1_j = work(u11+i+1,j)
326 work(u11+i,j)=work(cut+i,invd)*work(u11+i,j) +
327 $ work(cut+i,invd+1)*work(u11+i+1,j)
328 work(u11+i+1,j)=work(cut+i+1,invd)*u11_i_j+
329 $ work(cut+i+1,invd+1)*u11_ip1_j
330 END DO
331 i=i+2
332 END IF
333 END DO
334*
335* U11**T*invD1*U11->U11
336*
337 CALL ctrmm('L','U','T','U',nnb, nnb,
338 $ one,a(cut+1,cut+1),lda,work(u11+1,1),n+nb+1)
339*
340 DO i=1,nnb
341 DO j=i,nnb
342 a(cut+i,cut+j)=work(u11+i,j)
343 END DO
344 END DO
345*
346* U01**T*invD*U01->A(CUT+I,CUT+J)
347*
348 CALL cgemm('T','N',nnb,nnb,cut,one,a(1,cut+1),lda,
349 $ work,n+nb+1, zero, work(u11+1,1), n+nb+1)
350*
351* U11 = U11**T*invD1*U11 + U01**T*invD*U01
352*
353 DO i=1,nnb
354 DO j=i,nnb
355 a(cut+i,cut+j)=a(cut+i,cut+j)+work(u11+i,j)
356 END DO
357 END DO
358*
359* U01 = U00**T*invD0*U01
360*
361 CALL ctrmm('L',uplo,'T','U',cut, nnb,
362 $ one,a,lda,work,n+nb+1)
363
364*
365* Update U01
366*
367 DO i=1,cut
368 DO j=1,nnb
369 a(i,cut+j)=work(i,j)
370 END DO
371 END DO
372*
373* Next Block
374*
375 END DO
376*
377* Apply PERMUTATIONS P and P**T: P * inv(U**T)*inv(D)*inv(U) *P**T
378*
379 i=1
380 DO WHILE ( i .LE. n )
381 IF( ipiv(i) .GT. 0 ) THEN
382 ip=ipiv(i)
383 IF (i .LT. ip) CALL csyswapr( uplo, n, a, lda, i ,
384 $ ip )
385 IF (i .GT. ip) CALL csyswapr( uplo, n, a, lda, ip ,
386 $ i )
387 ELSE
388 ip=-ipiv(i)
389 i=i+1
390 IF ( (i-1) .LT. ip)
391 $ CALL csyswapr( uplo, n, a, lda, i-1 ,ip )
392 IF ( (i-1) .GT. ip)
393 $ CALL csyswapr( uplo, n, a, lda, ip ,i-1 )
394 ENDIF
395 i=i+1
396 END DO
397 ELSE
398*
399* LOWER...
400*
401* invA = P * inv(U**T)*inv(D)*inv(U)*P**T.
402*
403 CALL ctrtri( uplo, 'U', n, a, lda, info )
404*
405* inv(D) and inv(D)*inv(U)
406*
407 k=n
408 DO WHILE ( k .GE. 1 )
409 IF( ipiv( k ).GT.0 ) THEN
410* 1 x 1 diagonal NNB
411 work(k,invd) = one / a( k, k )
412 work(k,invd+1) = 0
413 k=k-1
414 ELSE
415* 2 x 2 diagonal NNB
416 t = work(k-1,1)
417 ak = a( k-1, k-1 ) / t
418 akp1 = a( k, k ) / t
419 akkp1 = work(k-1,1) / t
420 d = t*( ak*akp1-one )
421 work(k-1,invd) = akp1 / d
422 work(k,invd) = ak / d
423 work(k,invd+1) = -akkp1 / d
424 work(k-1,invd+1) = -akkp1 / d
425 k=k-2
426 END IF
427 END DO
428*
429* inv(U**T) = (inv(U))**T
430*
431* inv(U**T)*inv(D)*inv(U)
432*
433 cut=0
434 DO WHILE (cut .LT. n)
435 nnb=nb
436 IF (cut + nnb .GE. n) THEN
437 nnb=n-cut
438 ELSE
439 count = 0
440* count negative elements,
441 DO i=cut+1,cut+nnb
442 IF (ipiv(i) .LT. 0) count=count+1
443 END DO
444* need a even number for a clear cut
445 IF (mod(count,2) .EQ. 1) nnb=nnb+1
446 END IF
447* L21 Block
448 DO i=1,n-cut-nnb
449 DO j=1,nnb
450 work(i,j)=a(cut+nnb+i,cut+j)
451 END DO
452 END DO
453* L11 Block
454 DO i=1,nnb
455 work(u11+i,i)=one
456 DO j=i+1,nnb
457 work(u11+i,j)=zero
458 END DO
459 DO j=1,i-1
460 work(u11+i,j)=a(cut+i,cut+j)
461 END DO
462 END DO
463*
464* invD*L21
465*
466 i=n-cut-nnb
467 DO WHILE (i .GE. 1)
468 IF (ipiv(cut+nnb+i) > 0) THEN
469 DO j=1,nnb
470 work(i,j)=work(cut+nnb+i,invd)*work(i,j)
471 END DO
472 i=i-1
473 ELSE
474 DO j=1,nnb
475 u01_i_j = work(i,j)
476 u01_ip1_j = work(i-1,j)
477 work(i,j)=work(cut+nnb+i,invd)*u01_i_j+
478 $ work(cut+nnb+i,invd+1)*u01_ip1_j
479 work(i-1,j)=work(cut+nnb+i-1,invd+1)*u01_i_j+
480 $ work(cut+nnb+i-1,invd)*u01_ip1_j
481 END DO
482 i=i-2
483 END IF
484 END DO
485*
486* invD1*L11
487*
488 i=nnb
489 DO WHILE (i .GE. 1)
490 IF (ipiv(cut+i) > 0) THEN
491 DO j=1,nnb
492 work(u11+i,j)=work(cut+i,invd)*work(u11+i,j)
493 END DO
494 i=i-1
495 ELSE
496 DO j=1,nnb
497 u11_i_j = work(u11+i,j)
498 u11_ip1_j = work(u11+i-1,j)
499 work(u11+i,j)=work(cut+i,invd)*work(u11+i,j) +
500 $ work(cut+i,invd+1)*u11_ip1_j
501 work(u11+i-1,j)=work(cut+i-1,invd+1)*u11_i_j+
502 $ work(cut+i-1,invd)*u11_ip1_j
503 END DO
504 i=i-2
505 END IF
506 END DO
507*
508* L11**T*invD1*L11->L11
509*
510 CALL ctrmm('L',uplo,'T','U',nnb, nnb,
511 $ one,a(cut+1,cut+1),lda,work(u11+1,1),n+nb+1)
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* L21**T*invD2*L21->A(CUT+I,CUT+J)
522*
523 CALL cgemm('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* L11 = L11**T*invD1*L11 + U01**T*invD*U01
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* L01 = L22**T*invD2*L21
536*
537 CALL ctrmm('L',uplo,'T','U', n-nnb-cut, nnb,
538 $ one,a(cut+nnb+1,cut+nnb+1),lda,work,n+nb+1)
539
540* Update L21
541 DO i=1,n-cut-nnb
542 DO j=1,nnb
543 a(cut+nnb+i,cut+j)=work(i,j)
544 END DO
545 END DO
546 ELSE
547*
548* L11 = L11**T*invD1*L11
549*
550 DO i=1,nnb
551 DO j=1,i
552 a(cut+i,cut+j)=work(u11+i,j)
553 END DO
554 END DO
555 END IF
556*
557* Next Block
558*
559 cut=cut+nnb
560 END DO
561*
562* Apply PERMUTATIONS P and P**T: P * inv(U**T)*inv(D)*inv(U) *P**T
563*
564 i=n
565 DO WHILE ( i .GE. 1 )
566 IF( ipiv(i) .GT. 0 ) THEN
567 ip=ipiv(i)
568 IF (i .LT. ip) CALL csyswapr( uplo, n, a, lda, i ,
569 $ ip )
570 IF (i .GT. ip) CALL csyswapr( uplo, n, a, lda, ip ,
571 $ i )
572 ELSE
573 ip=-ipiv(i)
574 IF ( i .LT. ip) CALL csyswapr( uplo, n, a, lda, i ,
575 $ ip )
576 IF ( i .GT. ip) CALL csyswapr( uplo, n, a, lda, ip ,
577 $ i )
578 i=i-1
579 ENDIF
580 i=i-1
581 END DO
582 END IF
583*
584 RETURN
585*
586* End of CSYTRI2X
587*
588 END
589
subroutine xerbla(srname, info)
Definition cblat2.f:3285
subroutine cgemm(transa, transb, m, n, k, alpha, a, lda, b, ldb, beta, c, ldc)
CGEMM
Definition cgemm.f:188
subroutine csyswapr(uplo, n, a, lda, i1, i2)
CSYSWAPR
Definition csyswapr.f:98
subroutine csytri2x(uplo, n, a, lda, ipiv, work, nb, info)
CSYTRI2X
Definition csytri2x.f:118
subroutine csyconv(uplo, way, n, a, lda, ipiv, e, info)
CSYCONV
Definition csyconv.f:112
subroutine ctrmm(side, uplo, transa, diag, m, n, alpha, a, lda, b, ldb)
CTRMM
Definition ctrmm.f:177
subroutine ctrtri(uplo, diag, n, a, lda, info)
CTRTRI
Definition ctrtri.f:107