1 *> \brief \b CHETF2_ROOK computes the factorization of a complex Hermitian indefinite matrix using the bounded Bunch-Kaufman ("rook") diagonal pivoting method (unblocked algorithm).
3 * =========== DOCUMENTATION ===========
5 * Online html documentation available at
6 * http://www.netlib.org/lapack/explore-html/
9 *> Download CHETF2_ROOK + dependencies
10 *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/chetf2_rook.f">
12 *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/chetf2_rook.f">
14 *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/chetf2_rook.f">
21 * SUBROUTINE CHETF2_ROOK( UPLO, N, A, LDA, IPIV, INFO )
23 * .. Scalar Arguments ..
25 * INTEGER INFO, LDA, N
27 * .. Array Arguments ..
38 *> CHETF2_ROOK computes the factorization of a complex Hermitian matrix A
39 *> using the bounded Bunch-Kaufman ("rook") diagonal pivoting method:
41 *> A = U*D*U**H or A = L*D*L**H
43 *> where U (or L) is a product of permutation and unit upper (lower)
44 *> triangular matrices, U**H is the conjugate transpose of U, and D is
45 *> Hermitian and block diagonal with 1-by-1 and 2-by-2 diagonal blocks.
47 *> This is the unblocked version of the algorithm, calling Level 2 BLAS.
55 *> UPLO is CHARACTER*1
56 *> Specifies whether the upper or lower triangular part of the
57 *> Hermitian matrix A is stored:
58 *> = 'U': Upper triangular
59 *> = 'L': Lower triangular
65 *> The order of the matrix A. N >= 0.
70 *> A is COMPLEX array, dimension (LDA,N)
71 *> On entry, the Hermitian matrix A. If UPLO = 'U', the leading
72 *> n-by-n upper triangular part of A contains the upper
73 *> triangular part of the matrix A, and the strictly lower
74 *> triangular part of A is not referenced. If UPLO = 'L', the
75 *> leading n-by-n lower triangular part of A contains the lower
76 *> triangular part of the matrix A, and the strictly upper
77 *> triangular part of A is not referenced.
79 *> On exit, the block diagonal matrix D and the multipliers used
80 *> to obtain the factor U or L (see below for further details).
86 *> The leading dimension of the array A. LDA >= max(1,N).
91 *> IPIV is INTEGER array, dimension (N)
92 *> Details of the interchanges and the block structure of D.
95 *> If IPIV(k) > 0, then rows and columns k and IPIV(k) were
96 *> interchanged and D(k,k) is a 1-by-1 diagonal block.
98 *> If IPIV(k) < 0 and IPIV(k-1) < 0, then rows and
99 *> columns k and -IPIV(k) were interchanged and rows and
100 *> columns k-1 and -IPIV(k-1) were inerchaged,
101 *> D(k-1:k,k-1:k) is a 2-by-2 diagonal block.
104 *> If IPIV(k) > 0, then rows and columns k and IPIV(k)
105 *> were interchanged and D(k,k) is a 1-by-1 diagonal block.
107 *> If IPIV(k) < 0 and IPIV(k+1) < 0, then rows and
108 *> columns k and -IPIV(k) were interchanged and rows and
109 *> columns k+1 and -IPIV(k+1) were inerchaged,
110 *> D(k:k+1,k:k+1) is a 2-by-2 diagonal block.
116 *> = 0: successful exit
117 *> < 0: if INFO = -k, the k-th argument had an illegal value
118 *> > 0: if INFO = k, D(k,k) is exactly zero. The factorization
119 *> has been completed, but the block diagonal matrix D is
120 *> exactly singular, and division by zero will occur if it
121 *> is used to solve a system of equations.
127 *> \author Univ. of Tennessee
128 *> \author Univ. of California Berkeley
129 *> \author Univ. of Colorado Denver
132 *> \date November 2013
134 *> \ingroup complexHEcomputational
136 *> \par Further Details:
137 * =====================
141 *> If UPLO = 'U', then A = U*D*U**H, where
142 *> U = P(n)*U(n)* ... *P(k)U(k)* ...,
143 *> i.e., U is a product of terms P(k)*U(k), where k decreases from n to
144 *> 1 in steps of 1 or 2, and D is a block diagonal matrix with 1-by-1
145 *> and 2-by-2 diagonal blocks D(k). P(k) is a permutation matrix as
146 *> defined by IPIV(k), and U(k) is a unit upper triangular matrix, such
147 *> that if the diagonal block D(k) is of order s (s = 1 or 2), then
150 *> U(k) = ( 0 I 0 ) s
154 *> If s = 1, D(k) overwrites A(k,k), and v overwrites A(1:k-1,k).
155 *> If s = 2, the upper triangle of D(k) overwrites A(k-1,k-1), A(k-1,k),
156 *> and A(k,k), and v overwrites A(1:k-2,k-1:k).
158 *> If UPLO = 'L', then A = L*D*L**H, where
159 *> L = P(1)*L(1)* ... *P(k)*L(k)* ...,
160 *> i.e., L is a product of terms P(k)*L(k), where k increases from 1 to
161 *> n in steps of 1 or 2, and D is a block diagonal matrix with 1-by-1
162 *> and 2-by-2 diagonal blocks D(k). P(k) is a permutation matrix as
163 *> defined by IPIV(k), and L(k) is a unit lower triangular matrix, such
164 *> that if the diagonal block D(k) is of order s (s = 1 or 2), then
167 *> L(k) = ( 0 I 0 ) s
171 *> If s = 1, D(k) overwrites A(k,k), and v overwrites A(k+1:n,k).
172 *> If s = 2, the lower triangle of D(k) overwrites A(k,k), A(k+1,k),
173 *> and A(k+1,k+1), and v overwrites A(k+2:n,k:k+1).
176 *> \par Contributors:
181 *> November 2013, Igor Kozachenko,
182 *> Computer Science Division,
183 *> University of California, Berkeley
185 *> September 2007, Sven Hammarling, Nicholas J. Higham, Craig Lucas,
186 *> School of Mathematics,
187 *> University of Manchester
189 *> 01-01-96 - Based on modifications by
190 *> J. Lewis, Boeing Computer Services Company
191 *> A. Petitet, Computer Science Dept., Univ. of Tenn., Knoxville, USA
194 * =====================================================================
195 SUBROUTINE CHETF2_ROOK( UPLO, N, A, LDA, IPIV, INFO )
197 * -- LAPACK computational routine (version 3.5.0) --
198 * -- LAPACK is a software package provided by Univ. of Tennessee, --
199 * -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
202 * .. Scalar Arguments ..
206 * .. Array Arguments ..
211 * ======================================================================
215 PARAMETER ( ZERO = 0.0E+0, ONE = 1.0E+0 )
217 PARAMETER ( EIGHT = 8.0E+0, SEVTEN = 17.0E+0 )
219 * .. Local Scalars ..
221 INTEGER I, II, IMAX, ITEMP, J, JMAX, K, KK, KP, KSTEP,
223 REAL ABSAKK, ALPHA, COLMAX, D, D11, D22, R1, STEMP,
225 COMPLEX D12, D21, T, WK, WKM1, WKP1, Z
227 * .. External Functions ..
232 EXTERNAL LSAME, ICAMAX, SLAMCH, SLAPY2
234 * .. External Subroutines ..
235 EXTERNAL XERBLA, CSSCAL, CHER, CSWAP
237 * .. Intrinsic Functions ..
238 INTRINSIC ABS, AIMAG, CMPLX, CONJG, MAX, REAL, SQRT
240 * .. Statement Functions ..
243 * .. Statement Function definitions ..
244 CABS1( Z ) = ABS( REAL( Z ) ) + ABS( AIMAG( Z ) )
246 * .. Executable Statements ..
248 * Test the input parameters.
251 UPPER = LSAME( UPLO, 'U' )
252 IF( .NOT.UPPER .AND. .NOT.LSAME( UPLO, 'L' ) ) THEN
254 ELSE IF( N.LT.0 ) THEN
256 ELSE IF( LDA.LT.MAX( 1, N ) ) THEN
260 CALL XERBLA( 'CHETF2_ROOK', -INFO )
264 * Initialize ALPHA for use in choosing pivot block size.
266 ALPHA = ( ONE+SQRT( SEVTEN ) ) / EIGHT
268 * Compute machine safe minimum
270 SFMIN = SLAMCH( 'S' )
274 * Factorize A as U*D*U**H using the upper triangle of A
276 * K is the main loop index, decreasing from N to 1 in steps of
282 * If K < 1, exit from loop
289 * Determine rows and columns to be interchanged and whether
290 * a 1-by-1 or 2-by-2 pivot block will be used
292 ABSAKK = ABS( REAL( A( K, K ) ) )
294 * IMAX is the row-index of the largest off-diagonal element in
295 * column K, and COLMAX is its absolute value.
296 * Determine both COLMAX and IMAX.
299 IMAX = ICAMAX( K-1, A( 1, K ), 1 )
300 COLMAX = CABS1( A( IMAX, K ) )
305 IF( ( MAX( ABSAKK, COLMAX ).EQ.ZERO ) ) THEN
307 * Column K is zero or underflow: set INFO and continue
312 A( K, K ) = REAL( A( K, K ) )
315 * ============================================================
320 * Equivalent to testing for ABSAKK.GE.ALPHA*COLMAX
321 * (used to handle NaN and Inf)
323 IF( .NOT.( ABSAKK.LT.ALPHA*COLMAX ) ) THEN
325 * no interchange, use 1-by-1 pivot block
333 * Loop until pivot found
337 * BEGIN pivot search loop body
340 * JMAX is the column-index of the largest off-diagonal
341 * element in row IMAX, and ROWMAX is its absolute value.
342 * Determine both ROWMAX and JMAX.
345 JMAX = IMAX + ICAMAX( K-IMAX, A( IMAX, IMAX+1 ),
347 ROWMAX = CABS1( A( IMAX, JMAX ) )
353 ITEMP = ICAMAX( IMAX-1, A( 1, IMAX ), 1 )
354 STEMP = CABS1( A( ITEMP, IMAX ) )
355 IF( STEMP.GT.ROWMAX ) THEN
362 * Equivalent to testing for
363 * ABS( REAL( W( IMAX,KW-1 ) ) ).GE.ALPHA*ROWMAX
364 * (used to handle NaN and Inf)
366 IF( .NOT.( ABS( REAL( A( IMAX, IMAX ) ) )
367 $ .LT.ALPHA*ROWMAX ) ) THEN
369 * interchange rows and columns K and IMAX,
370 * use 1-by-1 pivot block
376 * Equivalent to testing for ROWMAX.EQ.COLMAX,
377 * (used to handle NaN and Inf)
379 ELSE IF( ( P.EQ.JMAX ) .OR. ( ROWMAX.LE.COLMAX ) )
382 * interchange rows and columns K-1 and IMAX,
383 * use 2-by-2 pivot block
392 * Pivot not found: set params and repeat
399 * END pivot search loop body
401 IF( .NOT.DONE ) GOTO 12
407 * ============================================================
409 * KK is the column of A where pivoting step stopped
413 * For only a 2x2 pivot, interchange rows and columns K and P
414 * in the leading submatrix A(1:k,1:k)
416 IF( ( KSTEP.EQ.2 ) .AND. ( P.NE.K ) ) THEN
417 * (1) Swap columnar parts
419 $ CALL CSWAP( P-1, A( 1, K ), 1, A( 1, P ), 1 )
420 * (2) Swap and conjugate middle parts
421 DO 14 J = P + 1, K - 1
422 T = CONJG( A( J, K ) )
423 A( J, K ) = CONJG( A( P, J ) )
426 * (3) Swap and conjugate corner elements at row-col interserction
427 A( P, K ) = CONJG( A( P, K ) )
428 * (4) Swap diagonal elements at row-col intersection
429 R1 = REAL( A( K, K ) )
430 A( K, K ) = REAL( A( P, P ) )
434 * For both 1x1 and 2x2 pivots, interchange rows and
435 * columns KK and KP in the leading submatrix A(1:k,1:k)
438 * (1) Swap columnar parts
440 $ CALL CSWAP( KP-1, A( 1, KK ), 1, A( 1, KP ), 1 )
441 * (2) Swap and conjugate middle parts
442 DO 15 J = KP + 1, KK - 1
443 T = CONJG( A( J, KK ) )
444 A( J, KK ) = CONJG( A( KP, J ) )
447 * (3) Swap and conjugate corner elements at row-col interserction
448 A( KP, KK ) = CONJG( A( KP, KK ) )
449 * (4) Swap diagonal elements at row-col intersection
450 R1 = REAL( A( KK, KK ) )
451 A( KK, KK ) = REAL( A( KP, KP ) )
454 IF( KSTEP.EQ.2 ) THEN
455 * (*) Make sure that diagonal element of pivot is real
456 A( K, K ) = REAL( A( K, K ) )
457 * (5) Swap row elements
459 A( K-1, K ) = A( KP, K )
463 * (*) Make sure that diagonal element of pivot is real
464 A( K, K ) = REAL( A( K, K ) )
466 $ A( K-1, K-1 ) = REAL( A( K-1, K-1 ) )
469 * Update the leading submatrix
471 IF( KSTEP.EQ.1 ) THEN
473 * 1-by-1 pivot block D(k): column k now holds
477 * where U(k) is the k-th column of U
481 * Perform a rank-1 update of A(1:k-1,1:k-1) and
482 * store U(k) in column k
484 IF( ABS( REAL( A( K, K ) ) ).GE.SFMIN ) THEN
486 * Perform a rank-1 update of A(1:k-1,1:k-1) as
487 * A := A - U(k)*D(k)*U(k)**T
488 * = A - W(k)*1/D(k)*W(k)**T
490 D11 = ONE / REAL( A( K, K ) )
491 CALL CHER( UPLO, K-1, -D11, A( 1, K ), 1, A, LDA )
493 * Store U(k) in column k
495 CALL CSSCAL( K-1, D11, A( 1, K ), 1 )
498 * Store L(k) in column K
500 D11 = REAL( A( K, K ) )
502 A( II, K ) = A( II, K ) / D11
505 * Perform a rank-1 update of A(k+1:n,k+1:n) as
506 * A := A - U(k)*D(k)*U(k)**T
507 * = A - W(k)*(1/D(k))*W(k)**T
508 * = A - (W(k)/D(k))*(D(k))*(W(k)/D(K))**T
510 CALL CHER( UPLO, K-1, -D11, A( 1, K ), 1, A, LDA )
516 * 2-by-2 pivot block D(k): columns k and k-1 now hold
518 * ( W(k-1) W(k) ) = ( U(k-1) U(k) )*D(k)
520 * where U(k) and U(k-1) are the k-th and (k-1)-th columns
523 * Perform a rank-2 update of A(1:k-2,1:k-2) as
525 * A := A - ( U(k-1) U(k) )*D(k)*( U(k-1) U(k) )**T
526 * = A - ( ( A(k-1)A(k) )*inv(D(k)) ) * ( A(k-1)A(k) )**T
528 * and store L(k) and L(k+1) in columns k and k+1
532 D = SLAPY2( REAL( A( K-1, K ) ),
533 $ AIMAG( A( K-1, K ) ) )
535 D22 = A( K-1, K-1 ) / D
536 D12 = A( K-1, K ) / D
537 TT = ONE / ( D11*D22-ONE )
539 DO 30 J = K - 2, 1, -1
541 * Compute D21 * ( W(k)W(k+1) ) * inv(D(k)) for row J
543 WKM1 = TT*( D11*A( J, K-1 )-CONJG( D12 )*
545 WK = TT*( D22*A( J, K )-D12*A( J, K-1 ) )
547 * Perform a rank-2 update of A(1:k-2,1:k-2)
550 A( I, J ) = A( I, J ) -
551 $ ( A( I, K ) / D )*CONJG( WK ) -
552 $ ( A( I, K-1 ) / D )*CONJG( WKM1 )
555 * Store U(k) and U(k-1) in cols k and k-1 for row J
558 A( J, K-1 ) = WKM1 / D
559 * (*) Make sure that diagonal element of pivot is real
560 A( J, J ) = CMPLX( REAL( A( J, J ) ), ZERO )
570 * Store details of the interchanges in IPIV
572 IF( KSTEP.EQ.1 ) THEN
579 * Decrease K and return to the start of the main loop
586 * Factorize A as L*D*L**H using the lower triangle of A
588 * K is the main loop index, increasing from 1 to N in steps of
594 * If K > N, exit from loop
601 * Determine rows and columns to be interchanged and whether
602 * a 1-by-1 or 2-by-2 pivot block will be used
604 ABSAKK = ABS( REAL( A( K, K ) ) )
606 * IMAX is the row-index of the largest off-diagonal element in
607 * column K, and COLMAX is its absolute value.
608 * Determine both COLMAX and IMAX.
611 IMAX = K + ICAMAX( N-K, A( K+1, K ), 1 )
612 COLMAX = CABS1( A( IMAX, K ) )
617 IF( MAX( ABSAKK, COLMAX ).EQ.ZERO ) THEN
619 * Column K is zero or underflow: set INFO and continue
624 A( K, K ) = REAL( A( K, K ) )
627 * ============================================================
632 * Equivalent to testing for ABSAKK.GE.ALPHA*COLMAX
633 * (used to handle NaN and Inf)
635 IF( .NOT.( ABSAKK.LT.ALPHA*COLMAX ) ) THEN
637 * no interchange, use 1-by-1 pivot block
645 * Loop until pivot found
649 * BEGIN pivot search loop body
652 * JMAX is the column-index of the largest off-diagonal
653 * element in row IMAX, and ROWMAX is its absolute value.
654 * Determine both ROWMAX and JMAX.
657 JMAX = K - 1 + ICAMAX( IMAX-K, A( IMAX, K ), LDA )
658 ROWMAX = CABS1( A( IMAX, JMAX ) )
664 ITEMP = IMAX + ICAMAX( N-IMAX, A( IMAX+1, IMAX ),
666 STEMP = CABS1( A( ITEMP, IMAX ) )
667 IF( STEMP.GT.ROWMAX ) THEN
674 * Equivalent to testing for
675 * ABS( REAL( W( IMAX,KW-1 ) ) ).GE.ALPHA*ROWMAX
676 * (used to handle NaN and Inf)
678 IF( .NOT.( ABS( REAL( A( IMAX, IMAX ) ) )
679 $ .LT.ALPHA*ROWMAX ) ) THEN
681 * interchange rows and columns K and IMAX,
682 * use 1-by-1 pivot block
688 * Equivalent to testing for ROWMAX.EQ.COLMAX,
689 * (used to handle NaN and Inf)
691 ELSE IF( ( P.EQ.JMAX ) .OR. ( ROWMAX.LE.COLMAX ) )
694 * interchange rows and columns K+1 and IMAX,
695 * use 2-by-2 pivot block
704 * Pivot not found: set params and repeat
712 * END pivot search loop body
714 IF( .NOT.DONE ) GOTO 42
720 * ============================================================
722 * KK is the column of A where pivoting step stopped
726 * For only a 2x2 pivot, interchange rows and columns K and P
727 * in the trailing submatrix A(k:n,k:n)
729 IF( ( KSTEP.EQ.2 ) .AND. ( P.NE.K ) ) THEN
730 * (1) Swap columnar parts
732 $ CALL CSWAP( N-P, A( P+1, K ), 1, A( P+1, P ), 1 )
733 * (2) Swap and conjugate middle parts
734 DO 44 J = K + 1, P - 1
735 T = CONJG( A( J, K ) )
736 A( J, K ) = CONJG( A( P, J ) )
739 * (3) Swap and conjugate corner elements at row-col interserction
740 A( P, K ) = CONJG( A( P, K ) )
741 * (4) Swap diagonal elements at row-col intersection
742 R1 = REAL( A( K, K ) )
743 A( K, K ) = REAL( A( P, P ) )
747 * For both 1x1 and 2x2 pivots, interchange rows and
748 * columns KK and KP in the trailing submatrix A(k:n,k:n)
751 * (1) Swap columnar parts
753 $ CALL CSWAP( N-KP, A( KP+1, KK ), 1, A( KP+1, KP ), 1 )
754 * (2) Swap and conjugate middle parts
755 DO 45 J = KK + 1, KP - 1
756 T = CONJG( A( J, KK ) )
757 A( J, KK ) = CONJG( A( KP, J ) )
760 * (3) Swap and conjugate corner elements at row-col interserction
761 A( KP, KK ) = CONJG( A( KP, KK ) )
762 * (4) Swap diagonal elements at row-col intersection
763 R1 = REAL( A( KK, KK ) )
764 A( KK, KK ) = REAL( A( KP, KP ) )
767 IF( KSTEP.EQ.2 ) THEN
768 * (*) Make sure that diagonal element of pivot is real
769 A( K, K ) = REAL( A( K, K ) )
770 * (5) Swap row elements
772 A( K+1, K ) = A( KP, K )
776 * (*) Make sure that diagonal element of pivot is real
777 A( K, K ) = REAL( A( K, K ) )
779 $ A( K+1, K+1 ) = REAL( A( K+1, K+1 ) )
782 * Update the trailing submatrix
784 IF( KSTEP.EQ.1 ) THEN
786 * 1-by-1 pivot block D(k): column k of A now holds
790 * where L(k) is the k-th column of L
794 * Perform a rank-1 update of A(k+1:n,k+1:n) and
795 * store L(k) in column k
797 * Handle division by a small number
799 IF( ABS( REAL( A( K, K ) ) ).GE.SFMIN ) THEN
801 * Perform a rank-1 update of A(k+1:n,k+1:n) as
802 * A := A - L(k)*D(k)*L(k)**T
803 * = A - W(k)*(1/D(k))*W(k)**T
805 D11 = ONE / REAL( A( K, K ) )
806 CALL CHER( UPLO, N-K, -D11, A( K+1, K ), 1,
807 $ A( K+1, K+1 ), LDA )
809 * Store L(k) in column k
811 CALL CSSCAL( N-K, D11, A( K+1, K ), 1 )
814 * Store L(k) in column k
816 D11 = REAL( A( K, K ) )
818 A( II, K ) = A( II, K ) / D11
821 * Perform a rank-1 update of A(k+1:n,k+1:n) as
822 * A := A - L(k)*D(k)*L(k)**T
823 * = A - W(k)*(1/D(k))*W(k)**T
824 * = A - (W(k)/D(k))*(D(k))*(W(k)/D(K))**T
826 CALL CHER( UPLO, N-K, -D11, A( K+1, K ), 1,
827 $ A( K+1, K+1 ), LDA )
833 * 2-by-2 pivot block D(k): columns k and k+1 now hold
835 * ( W(k) W(k+1) ) = ( L(k) L(k+1) )*D(k)
837 * where L(k) and L(k+1) are the k-th and (k+1)-th columns
841 * Perform a rank-2 update of A(k+2:n,k+2:n) as
843 * A := A - ( L(k) L(k+1) ) * D(k) * ( L(k) L(k+1) )**T
844 * = A - ( ( A(k)A(k+1) )*inv(D(k) ) * ( A(k)A(k+1) )**T
846 * and store L(k) and L(k+1) in columns k and k+1
850 D = SLAPY2( REAL( A( K+1, K ) ),
851 $ AIMAG( A( K+1, K ) ) )
852 D11 = REAL( A( K+1, K+1 ) ) / D
853 D22 = REAL( A( K, K ) ) / D
854 D21 = A( K+1, K ) / D
855 TT = ONE / ( D11*D22-ONE )
859 * Compute D21 * ( W(k)W(k+1) ) * inv(D(k)) for row J
861 WK = TT*( D11*A( J, K )-D21*A( J, K+1 ) )
862 WKP1 = TT*( D22*A( J, K+1 )-CONJG( D21 )*
865 * Perform a rank-2 update of A(k+2:n,k+2:n)
868 A( I, J ) = A( I, J ) -
869 $ ( A( I, K ) / D )*CONJG( WK ) -
870 $ ( A( I, K+1 ) / D )*CONJG( WKP1 )
873 * Store L(k) and L(k+1) in cols k and k+1 for row J
876 A( J, K+1 ) = WKP1 / D
877 * (*) Make sure that diagonal element of pivot is real
878 A( J, J ) = CMPLX( REAL( A( J, J ) ), ZERO )
888 * Store details of the interchanges in IPIV
890 IF( KSTEP.EQ.1 ) THEN
897 * Increase K and return to the start of the main loop