1 *> \brief \b CSYTF2_ROOK computes the factorization of a complex symmetric 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 CSYTF2_ROOK + dependencies
10 *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/csytf2_rook.f">
12 *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/csytf2_rook.f">
14 *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/csytf2_rook.f">
21 * SUBROUTINE CSYTF2_ROOK( UPLO, N, A, LDA, IPIV, INFO )
23 * .. Scalar Arguments ..
25 * INTEGER INFO, LDA, N
27 * .. Array Arguments ..
38 *> CSYTF2_ROOK computes the factorization of a complex symmetric matrix A
39 *> using the bounded Bunch-Kaufman ("rook") diagonal pivoting method:
41 *> A = U*D*U**T or A = L*D*L**T
43 *> where U (or L) is a product of permutation and unit upper (lower)
44 *> triangular matrices, U**T is the transpose of U, and D is symmetric and
45 *> 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 *> symmetric 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 symmetric 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)
96 *> were 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 complexSYcomputational
136 *> \par Further Details:
137 * =====================
141 *> If UPLO = 'U', then A = U*D*U**T, 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**T, 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 abd , USA
194 * =====================================================================
195 SUBROUTINE CSYTF2_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 PARAMETER ( CONE = ( 1.0E+0, 0.0E+0 ) )
221 * .. Local Scalars ..
223 INTEGER I, IMAX, J, JMAX, ITEMP, K, KK, KP, KSTEP,
225 REAL ABSAKK, ALPHA, COLMAX, ROWMAX, STEMP, SFMIN
226 COMPLEX D11, D12, D21, D22, T, WK, WKM1, WKP1, Z
228 * .. External Functions ..
232 EXTERNAL LSAME, ICAMAX, SLAMCH
234 * .. External Subroutines ..
235 EXTERNAL CSCAL, CSWAP, CSYR, XERBLA
237 * .. Intrinsic Functions ..
238 INTRINSIC ABS, MAX, SQRT, AIMAG, REAL
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( 'CSYTF2_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**T 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 = CABS1( 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
314 * Test for interchange
316 * Equivalent to testing for (used to handle NaN and Inf)
317 * ABSAKK.GE.ALPHA*COLMAX
319 IF( .NOT.( ABSAKK.LT.ALPHA*COLMAX ) ) THEN
322 * use 1-by-1 pivot block
329 * Loop until pivot found
333 * Begin pivot search loop body
335 * JMAX is the column-index of the largest off-diagonal
336 * element in row IMAX, and ROWMAX is its absolute value.
337 * Determine both ROWMAX and JMAX.
340 JMAX = IMAX + ICAMAX( K-IMAX, A( IMAX, IMAX+1 ),
342 ROWMAX = CABS1( A( IMAX, JMAX ) )
348 ITEMP = ICAMAX( IMAX-1, A( 1, IMAX ), 1 )
349 STEMP = CABS1( A( ITEMP, IMAX ) )
350 IF( STEMP.GT.ROWMAX ) THEN
356 * Equivalent to testing for (used to handle NaN and Inf)
357 * CABS1( A( IMAX, IMAX ) ).GE.ALPHA*ROWMAX
359 IF( .NOT.( CABS1(A( IMAX, IMAX )).LT.ALPHA*ROWMAX ) )
362 * interchange rows and columns K and IMAX,
363 * use 1-by-1 pivot block
368 * Equivalent to testing for ROWMAX .EQ. COLMAX,
369 * used to handle NaN and Inf
371 ELSE IF( ( P.EQ.JMAX ).OR.( ROWMAX.LE.COLMAX ) ) THEN
373 * interchange rows and columns K+1 and IMAX,
374 * use 2-by-2 pivot block
381 * Pivot NOT found, set variables and repeat
388 * End pivot search loop body
390 IF( .NOT. DONE ) GOTO 12
394 * Swap TWO rows and TWO columns
398 IF( ( KSTEP.EQ.2 ) .AND. ( P.NE.K ) ) THEN
400 * Interchange rows and column K and P in the leading
401 * submatrix A(1:k,1:k) if we have a 2-by-2 pivot
404 $ CALL CSWAP( P-1, A( 1, K ), 1, A( 1, P ), 1 )
406 $ CALL CSWAP( K-P-1, A( P+1, K ), 1, A( P, P+1 ),
409 A( K, K ) = A( P, P )
418 * Interchange rows and columns KK and KP in the leading
419 * submatrix A(1:k,1:k)
422 $ CALL CSWAP( KP-1, A( 1, KK ), 1, A( 1, KP ), 1 )
423 IF( ( KK.GT.1 ) .AND. ( KP.LT.(KK-1) ) )
424 $ CALL CSWAP( KK-KP-1, A( KP+1, KK ), 1, A( KP, KP+1 ),
427 A( KK, KK ) = A( KP, KP )
429 IF( KSTEP.EQ.2 ) THEN
431 A( K-1, K ) = A( KP, K )
436 * Update the leading submatrix
438 IF( KSTEP.EQ.1 ) THEN
440 * 1-by-1 pivot block D(k): column k now holds
444 * where U(k) is the k-th column of U
448 * Perform a rank-1 update of A(1:k-1,1:k-1) and
449 * store U(k) in column k
451 IF( CABS1( A( K, K ) ).GE.SFMIN ) THEN
453 * Perform a rank-1 update of A(1:k-1,1:k-1) as
454 * A := A - U(k)*D(k)*U(k)**T
455 * = A - W(k)*1/D(k)*W(k)**T
457 D11 = CONE / A( K, K )
458 CALL CSYR( UPLO, K-1, -D11, A( 1, K ), 1, A, LDA )
460 * Store U(k) in column k
462 CALL CSCAL( K-1, D11, A( 1, K ), 1 )
465 * Store L(k) in column K
469 A( II, K ) = A( II, K ) / D11
472 * Perform a rank-1 update of A(k+1:n,k+1:n) as
473 * A := A - U(k)*D(k)*U(k)**T
474 * = A - W(k)*(1/D(k))*W(k)**T
475 * = A - (W(k)/D(k))*(D(k))*(W(k)/D(K))**T
477 CALL CSYR( UPLO, K-1, -D11, A( 1, K ), 1, A, LDA )
483 * 2-by-2 pivot block D(k): columns k and k-1 now hold
485 * ( W(k-1) W(k) ) = ( U(k-1) U(k) )*D(k)
487 * where U(k) and U(k-1) are the k-th and (k-1)-th columns
490 * Perform a rank-2 update of A(1:k-2,1:k-2) as
492 * A := A - ( U(k-1) U(k) )*D(k)*( U(k-1) U(k) )**T
493 * = A - ( ( A(k-1)A(k) )*inv(D(k)) ) * ( A(k-1)A(k) )**T
495 * and store L(k) and L(k+1) in columns k and k+1
500 D22 = A( K-1, K-1 ) / D12
501 D11 = A( K, K ) / D12
502 T = CONE / ( D11*D22-CONE )
504 DO 30 J = K - 2, 1, -1
506 WKM1 = T*( D11*A( J, K-1 )-A( J, K ) )
507 WK = T*( D22*A( J, K )-A( J, K-1 ) )
510 A( I, J ) = A( I, J ) - (A( I, K ) / D12 )*WK -
511 $ ( A( I, K-1 ) / D12 )*WKM1
514 * Store U(k) and U(k-1) in cols k and k-1 for row J
517 A( J, K-1 ) = WKM1 / D12
526 * Store details of the interchanges in IPIV
528 IF( KSTEP.EQ.1 ) THEN
535 * Decrease K and return to the start of the main loop
542 * Factorize A as L*D*L**T using the lower triangle of A
544 * K is the main loop index, increasing from 1 to N in steps of
550 * If K > N, exit from loop
557 * Determine rows and columns to be interchanged and whether
558 * a 1-by-1 or 2-by-2 pivot block will be used
560 ABSAKK = CABS1( A( K, K ) )
562 * IMAX is the row-index of the largest off-diagonal element in
563 * column K, and COLMAX is its absolute value.
564 * Determine both COLMAX and IMAX.
567 IMAX = K + ICAMAX( N-K, A( K+1, K ), 1 )
568 COLMAX = CABS1( A( IMAX, K ) )
573 IF( ( MAX( ABSAKK, COLMAX ).EQ.ZERO ) ) THEN
575 * Column K is zero or underflow: set INFO and continue
582 * Test for interchange
584 * Equivalent to testing for (used to handle NaN and Inf)
585 * ABSAKK.GE.ALPHA*COLMAX
587 IF( .NOT.( ABSAKK.LT.ALPHA*COLMAX ) ) THEN
589 * no interchange, use 1-by-1 pivot block
596 * Loop until pivot found
600 * Begin pivot search loop body
602 * JMAX is the column-index of the largest off-diagonal
603 * element in row IMAX, and ROWMAX is its absolute value.
604 * Determine both ROWMAX and JMAX.
607 JMAX = K - 1 + ICAMAX( IMAX-K, A( IMAX, K ), LDA )
608 ROWMAX = CABS1( A( IMAX, JMAX ) )
614 ITEMP = IMAX + ICAMAX( N-IMAX, A( IMAX+1, IMAX ),
616 STEMP = CABS1( A( ITEMP, IMAX ) )
617 IF( STEMP.GT.ROWMAX ) THEN
623 * Equivalent to testing for (used to handle NaN and Inf)
624 * CABS1( A( IMAX, IMAX ) ).GE.ALPHA*ROWMAX
626 IF( .NOT.( CABS1(A( IMAX, IMAX )).LT.ALPHA*ROWMAX ) )
629 * interchange rows and columns K and IMAX,
630 * use 1-by-1 pivot block
635 * Equivalent to testing for ROWMAX .EQ. COLMAX,
636 * used to handle NaN and Inf
638 ELSE IF( ( P.EQ.JMAX ).OR.( ROWMAX.LE.COLMAX ) ) THEN
640 * interchange rows and columns K+1 and IMAX,
641 * use 2-by-2 pivot block
648 * Pivot NOT found, set variables and repeat
655 * End pivot search loop body
657 IF( .NOT. DONE ) GOTO 42
661 * Swap TWO rows and TWO columns
665 IF( ( KSTEP.EQ.2 ) .AND. ( P.NE.K ) ) THEN
667 * Interchange rows and column K and P in the trailing
668 * submatrix A(k:n,k:n) if we have a 2-by-2 pivot
671 $ CALL CSWAP( N-P, A( P+1, K ), 1, A( P+1, P ), 1 )
673 $ CALL CSWAP( P-K-1, A( K+1, K ), 1, A( P, K+1 ), LDA )
675 A( K, K ) = A( P, P )
684 * Interchange rows and columns KK and KP in the trailing
685 * submatrix A(k:n,k:n)
688 $ CALL CSWAP( N-KP, A( KP+1, KK ), 1, A( KP+1, KP ), 1 )
689 IF( ( KK.LT.N ) .AND. ( KP.GT.(KK+1) ) )
690 $ CALL CSWAP( KP-KK-1, A( KK+1, KK ), 1, A( KP, KK+1 ),
693 A( KK, KK ) = A( KP, KP )
695 IF( KSTEP.EQ.2 ) THEN
697 A( K+1, K ) = A( KP, K )
702 * Update the trailing submatrix
704 IF( KSTEP.EQ.1 ) THEN
706 * 1-by-1 pivot block D(k): column k now holds
710 * where L(k) is the k-th column of L
714 * Perform a rank-1 update of A(k+1:n,k+1:n) and
715 * store L(k) in column k
717 IF( CABS1( A( K, K ) ).GE.SFMIN ) THEN
719 * Perform a rank-1 update of A(k+1:n,k+1:n) as
720 * A := A - L(k)*D(k)*L(k)**T
721 * = A - W(k)*(1/D(k))*W(k)**T
723 D11 = CONE / A( K, K )
724 CALL CSYR( UPLO, N-K, -D11, A( K+1, K ), 1,
725 $ A( K+1, K+1 ), LDA )
727 * Store L(k) in column k
729 CALL CSCAL( N-K, D11, A( K+1, K ), 1 )
732 * Store L(k) in column k
736 A( II, K ) = A( II, K ) / D11
739 * Perform a rank-1 update of A(k+1:n,k+1:n) as
740 * A := A - L(k)*D(k)*L(k)**T
741 * = A - W(k)*(1/D(k))*W(k)**T
742 * = A - (W(k)/D(k))*(D(k))*(W(k)/D(K))**T
744 CALL CSYR( UPLO, N-K, -D11, A( K+1, K ), 1,
745 $ A( K+1, K+1 ), LDA )
751 * 2-by-2 pivot block D(k): columns k and k+1 now hold
753 * ( W(k) W(k+1) ) = ( L(k) L(k+1) )*D(k)
755 * where L(k) and L(k+1) are the k-th and (k+1)-th columns
759 * Perform a rank-2 update of A(k+2:n,k+2:n) as
761 * A := A - ( L(k) L(k+1) ) * D(k) * ( L(k) L(k+1) )**T
762 * = A - ( ( A(k)A(k+1) )*inv(D(k) ) * ( A(k)A(k+1) )**T
764 * and store L(k) and L(k+1) in columns k and k+1
769 D11 = A( K+1, K+1 ) / D21
770 D22 = A( K, K ) / D21
771 T = CONE / ( D11*D22-CONE )
775 * Compute D21 * ( W(k)W(k+1) ) * inv(D(k)) for row J
777 WK = T*( D11*A( J, K )-A( J, K+1 ) )
778 WKP1 = T*( D22*A( J, K+1 )-A( J, K ) )
780 * Perform a rank-2 update of A(k+2:n,k+2:n)
783 A( I, J ) = A( I, J ) - ( A( I, K ) / D21 )*WK -
784 $ ( A( I, K+1 ) / D21 )*WKP1
787 * Store L(k) and L(k+1) in cols k and k+1 for row J
790 A( J, K+1 ) = WKP1 / D21
799 * Store details of the interchanges in IPIV
801 IF( KSTEP.EQ.1 ) THEN
808 * Increase K and return to the start of the main loop