LAPACK 3.12.0
LAPACK: Linear Algebra PACKage
Loading...
Searching...
No Matches
zlahef.f
Go to the documentation of this file.
1*> \brief \b ZLAHEF computes a partial factorization of a complex Hermitian indefinite matrix using the Bunch-Kaufman diagonal pivoting method (blocked algorithm, calling Level 3 BLAS).
2*
3* =========== DOCUMENTATION ===========
4*
5* Online html documentation available at
6* http://www.netlib.org/lapack/explore-html/
7*
8*> \htmlonly
9*> Download ZLAHEF + dependencies
10*> <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/zlahef.f">
11*> [TGZ]</a>
12*> <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/zlahef.f">
13*> [ZIP]</a>
14*> <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/zlahef.f">
15*> [TXT]</a>
16*> \endhtmlonly
17*
18* Definition:
19* ===========
20*
21* SUBROUTINE ZLAHEF( UPLO, N, NB, KB, A, LDA, IPIV, W, LDW, INFO )
22*
23* .. Scalar Arguments ..
24* CHARACTER UPLO
25* INTEGER INFO, KB, LDA, LDW, N, NB
26* ..
27* .. Array Arguments ..
28* INTEGER IPIV( * )
29* COMPLEX*16 A( LDA, * ), W( LDW, * )
30* ..
31*
32*
33*> \par Purpose:
34* =============
35*>
36*> \verbatim
37*>
38*> ZLAHEF computes a partial factorization of a complex Hermitian
39*> matrix A using the Bunch-Kaufman diagonal pivoting method. The
40*> partial factorization has the form:
41*>
42*> A = ( I U12 ) ( A11 0 ) ( I 0 ) if UPLO = 'U', or:
43*> ( 0 U22 ) ( 0 D ) ( U12**H U22**H )
44*>
45*> A = ( L11 0 ) ( D 0 ) ( L11**H L21**H ) if UPLO = 'L'
46*> ( L21 I ) ( 0 A22 ) ( 0 I )
47*>
48*> where the order of D is at most NB. The actual order is returned in
49*> the argument KB, and is either NB or NB-1, or N if N <= NB.
50*> Note that U**H denotes the conjugate transpose of U.
51*>
52*> ZLAHEF is an auxiliary routine called by ZHETRF. It uses blocked code
53*> (calling Level 3 BLAS) to update the submatrix A11 (if UPLO = 'U') or
54*> A22 (if UPLO = 'L').
55*> \endverbatim
56*
57* Arguments:
58* ==========
59*
60*> \param[in] UPLO
61*> \verbatim
62*> UPLO is CHARACTER*1
63*> Specifies whether the upper or lower triangular part of the
64*> Hermitian matrix A is stored:
65*> = 'U': Upper triangular
66*> = 'L': Lower triangular
67*> \endverbatim
68*>
69*> \param[in] N
70*> \verbatim
71*> N is INTEGER
72*> The order of the matrix A. N >= 0.
73*> \endverbatim
74*>
75*> \param[in] NB
76*> \verbatim
77*> NB is INTEGER
78*> The maximum number of columns of the matrix A that should be
79*> factored. NB should be at least 2 to allow for 2-by-2 pivot
80*> blocks.
81*> \endverbatim
82*>
83*> \param[out] KB
84*> \verbatim
85*> KB is INTEGER
86*> The number of columns of A that were actually factored.
87*> KB is either NB-1 or NB, or N if N <= NB.
88*> \endverbatim
89*>
90*> \param[in,out] A
91*> \verbatim
92*> A is COMPLEX*16 array, dimension (LDA,N)
93*> On entry, the Hermitian matrix A. If UPLO = 'U', the leading
94*> n-by-n upper triangular part of A contains the upper
95*> triangular part of the matrix A, and the strictly lower
96*> triangular part of A is not referenced. If UPLO = 'L', the
97*> leading n-by-n lower triangular part of A contains the lower
98*> triangular part of the matrix A, and the strictly upper
99*> triangular part of A is not referenced.
100*> On exit, A contains details of the partial factorization.
101*> \endverbatim
102*>
103*> \param[in] LDA
104*> \verbatim
105*> LDA is INTEGER
106*> The leading dimension of the array A. LDA >= max(1,N).
107*> \endverbatim
108*>
109*> \param[out] IPIV
110*> \verbatim
111*> IPIV is INTEGER array, dimension (N)
112*> Details of the interchanges and the block structure of D.
113*>
114*> If UPLO = 'U':
115*> Only the last KB elements of IPIV are set.
116*>
117*> If IPIV(k) > 0, then rows and columns k and IPIV(k) were
118*> interchanged and D(k,k) is a 1-by-1 diagonal block.
119*>
120*> If IPIV(k) = IPIV(k-1) < 0, then rows and columns
121*> k-1 and -IPIV(k) were interchanged and D(k-1:k,k-1:k)
122*> is a 2-by-2 diagonal block.
123*>
124*> If UPLO = 'L':
125*> Only the first KB elements of IPIV are set.
126*>
127*> If IPIV(k) > 0, then rows and columns k and IPIV(k) were
128*> interchanged and D(k,k) is a 1-by-1 diagonal block.
129*>
130*> If IPIV(k) = IPIV(k+1) < 0, then rows and columns
131*> k+1 and -IPIV(k) were interchanged and D(k:k+1,k:k+1)
132*> is a 2-by-2 diagonal block.
133*> \endverbatim
134*>
135*> \param[out] W
136*> \verbatim
137*> W is COMPLEX*16 array, dimension (LDW,NB)
138*> \endverbatim
139*>
140*> \param[in] LDW
141*> \verbatim
142*> LDW is INTEGER
143*> The leading dimension of the array W. LDW >= max(1,N).
144*> \endverbatim
145*>
146*> \param[out] INFO
147*> \verbatim
148*> INFO is INTEGER
149*> = 0: successful exit
150*> > 0: if INFO = k, D(k,k) is exactly zero. The factorization
151*> has been completed, but the block diagonal matrix D is
152*> exactly singular.
153*> \endverbatim
154*
155* Authors:
156* ========
157*
158*> \author Univ. of Tennessee
159*> \author Univ. of California Berkeley
160*> \author Univ. of Colorado Denver
161*> \author NAG Ltd.
162*
163*> \ingroup lahef
164*
165*> \par Contributors:
166* ==================
167*>
168*> \verbatim
169*>
170*> December 2016, Igor Kozachenko,
171*> Computer Science Division,
172*> University of California, Berkeley
173*> \endverbatim
174*
175* =====================================================================
176 SUBROUTINE zlahef( UPLO, N, NB, KB, A, LDA, IPIV, W, LDW, INFO )
177*
178* -- LAPACK computational routine --
179* -- LAPACK is a software package provided by Univ. of Tennessee, --
180* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
181*
182* .. Scalar Arguments ..
183 CHARACTER UPLO
184 INTEGER INFO, KB, LDA, LDW, N, NB
185* ..
186* .. Array Arguments ..
187 INTEGER IPIV( * )
188 COMPLEX*16 A( LDA, * ), W( LDW, * )
189* ..
190*
191* =====================================================================
192*
193* .. Parameters ..
194 DOUBLE PRECISION ZERO, ONE
195 parameter( zero = 0.0d+0, one = 1.0d+0 )
196 COMPLEX*16 CONE
197 parameter( cone = ( 1.0d+0, 0.0d+0 ) )
198 DOUBLE PRECISION EIGHT, SEVTEN
199 parameter( eight = 8.0d+0, sevten = 17.0d+0 )
200* ..
201* .. Local Scalars ..
202 INTEGER IMAX, J, JB, JJ, JMAX, JP, K, KK, KKW, KP,
203 $ KSTEP, KW
204 DOUBLE PRECISION ABSAKK, ALPHA, COLMAX, R1, ROWMAX, T
205 COMPLEX*16 D11, D21, D22, Z
206* ..
207* .. External Functions ..
208 LOGICAL LSAME
209 INTEGER IZAMAX
210 EXTERNAL lsame, izamax
211* ..
212* .. External Subroutines ..
213 EXTERNAL zcopy, zdscal, zgemm, zgemv, zlacgv, zswap
214* ..
215* .. Intrinsic Functions ..
216 INTRINSIC abs, dble, dconjg, dimag, max, min, sqrt
217* ..
218* .. Statement Functions ..
219 DOUBLE PRECISION CABS1
220* ..
221* .. Statement Function definitions ..
222 cabs1( z ) = abs( dble( z ) ) + abs( dimag( z ) )
223* ..
224* .. Executable Statements ..
225*
226 info = 0
227*
228* Initialize ALPHA for use in choosing pivot block size.
229*
230 alpha = ( one+sqrt( sevten ) ) / eight
231*
232 IF( lsame( uplo, 'U' ) ) THEN
233*
234* Factorize the trailing columns of A using the upper triangle
235* of A and working backwards, and compute the matrix W = U12*D
236* for use in updating A11 (note that conjg(W) is actually stored)
237*
238* K is the main loop index, decreasing from N in steps of 1 or 2
239*
240* KW is the column of W which corresponds to column K of A
241*
242 k = n
243 10 CONTINUE
244 kw = nb + k - n
245*
246* Exit from loop
247*
248 IF( ( k.LE.n-nb+1 .AND. nb.LT.n ) .OR. k.LT.1 )
249 $ GO TO 30
250*
251 kstep = 1
252*
253* Copy column K of A to column KW of W and update it
254*
255 CALL zcopy( k-1, a( 1, k ), 1, w( 1, kw ), 1 )
256 w( k, kw ) = dble( a( k, k ) )
257 IF( k.LT.n ) THEN
258 CALL zgemv( 'No transpose', k, n-k, -cone, a( 1, k+1 ), lda,
259 $ w( k, kw+1 ), ldw, cone, w( 1, kw ), 1 )
260 w( k, kw ) = dble( w( k, kw ) )
261 END IF
262*
263* Determine rows and columns to be interchanged and whether
264* a 1-by-1 or 2-by-2 pivot block will be used
265*
266 absakk = abs( dble( w( k, kw ) ) )
267*
268* IMAX is the row-index of the largest off-diagonal element in
269* column K, and COLMAX is its absolute value.
270* Determine both COLMAX and IMAX.
271*
272 IF( k.GT.1 ) THEN
273 imax = izamax( k-1, w( 1, kw ), 1 )
274 colmax = cabs1( w( imax, kw ) )
275 ELSE
276 colmax = zero
277 END IF
278*
279 IF( max( absakk, colmax ).EQ.zero ) THEN
280*
281* Column K is zero or underflow: set INFO and continue
282*
283 IF( info.EQ.0 )
284 $ info = k
285 kp = k
286 a( k, k ) = dble( a( k, k ) )
287 ELSE
288*
289* ============================================================
290*
291* BEGIN pivot search
292*
293* Case(1)
294 IF( absakk.GE.alpha*colmax ) THEN
295*
296* no interchange, use 1-by-1 pivot block
297*
298 kp = k
299 ELSE
300*
301* BEGIN pivot search along IMAX row
302*
303*
304* Copy column IMAX to column KW-1 of W and update it
305*
306 CALL zcopy( imax-1, a( 1, imax ), 1, w( 1, kw-1 ), 1 )
307 w( imax, kw-1 ) = dble( a( imax, imax ) )
308 CALL zcopy( k-imax, a( imax, imax+1 ), lda,
309 $ w( imax+1, kw-1 ), 1 )
310 CALL zlacgv( k-imax, w( imax+1, kw-1 ), 1 )
311 IF( k.LT.n ) THEN
312 CALL zgemv( 'No transpose', k, n-k, -cone,
313 $ a( 1, k+1 ), lda, w( imax, kw+1 ), ldw,
314 $ cone, w( 1, kw-1 ), 1 )
315 w( imax, kw-1 ) = dble( w( imax, kw-1 ) )
316 END IF
317*
318* JMAX is the column-index of the largest off-diagonal
319* element in row IMAX, and ROWMAX is its absolute value.
320* Determine only ROWMAX.
321*
322 jmax = imax + izamax( k-imax, w( imax+1, kw-1 ), 1 )
323 rowmax = cabs1( w( jmax, kw-1 ) )
324 IF( imax.GT.1 ) THEN
325 jmax = izamax( imax-1, w( 1, kw-1 ), 1 )
326 rowmax = max( rowmax, cabs1( w( jmax, kw-1 ) ) )
327 END IF
328*
329* Case(2)
330 IF( absakk.GE.alpha*colmax*( colmax / rowmax ) ) THEN
331*
332* no interchange, use 1-by-1 pivot block
333*
334 kp = k
335*
336* Case(3)
337 ELSE IF( abs( dble( w( imax, kw-1 ) ) ).GE.alpha*rowmax )
338 $ THEN
339*
340* interchange rows and columns K and IMAX, use 1-by-1
341* pivot block
342*
343 kp = imax
344*
345* copy column KW-1 of W to column KW of W
346*
347 CALL zcopy( k, w( 1, kw-1 ), 1, w( 1, kw ), 1 )
348*
349* Case(4)
350 ELSE
351*
352* interchange rows and columns K-1 and IMAX, use 2-by-2
353* pivot block
354*
355 kp = imax
356 kstep = 2
357 END IF
358*
359*
360* END pivot search along IMAX row
361*
362 END IF
363*
364* END pivot search
365*
366* ============================================================
367*
368* KK is the column of A where pivoting step stopped
369*
370 kk = k - kstep + 1
371*
372* KKW is the column of W which corresponds to column KK of A
373*
374 kkw = nb + kk - n
375*
376* Interchange rows and columns KP and KK.
377* Updated column KP is already stored in column KKW of W.
378*
379 IF( kp.NE.kk ) THEN
380*
381* Copy non-updated column KK to column KP of submatrix A
382* at step K. No need to copy element into column K
383* (or K and K-1 for 2-by-2 pivot) of A, since these columns
384* will be later overwritten.
385*
386 a( kp, kp ) = dble( a( kk, kk ) )
387 CALL zcopy( kk-1-kp, a( kp+1, kk ), 1, a( kp, kp+1 ),
388 $ lda )
389 CALL zlacgv( kk-1-kp, a( kp, kp+1 ), lda )
390 IF( kp.GT.1 )
391 $ CALL zcopy( kp-1, a( 1, kk ), 1, a( 1, kp ), 1 )
392*
393* Interchange rows KK and KP in last K+1 to N columns of A
394* (columns K (or K and K-1 for 2-by-2 pivot) of A will be
395* later overwritten). Interchange rows KK and KP
396* in last KKW to NB columns of W.
397*
398 IF( k.LT.n )
399 $ CALL zswap( n-k, a( kk, k+1 ), lda, a( kp, k+1 ),
400 $ lda )
401 CALL zswap( n-kk+1, w( kk, kkw ), ldw, w( kp, kkw ),
402 $ ldw )
403 END IF
404*
405 IF( kstep.EQ.1 ) THEN
406*
407* 1-by-1 pivot block D(k): column kw of W now holds
408*
409* W(kw) = U(k)*D(k),
410*
411* where U(k) is the k-th column of U
412*
413* (1) Store subdiag. elements of column U(k)
414* and 1-by-1 block D(k) in column k of A.
415* (NOTE: Diagonal element U(k,k) is a UNIT element
416* and not stored)
417* A(k,k) := D(k,k) = W(k,kw)
418* A(1:k-1,k) := U(1:k-1,k) = W(1:k-1,kw)/D(k,k)
419*
420* (NOTE: No need to use for Hermitian matrix
421* A( K, K ) = DBLE( W( K, K) ) to separately copy diagonal
422* element D(k,k) from W (potentially saves only one load))
423 CALL zcopy( k, w( 1, kw ), 1, a( 1, k ), 1 )
424 IF( k.GT.1 ) THEN
425*
426* (NOTE: No need to check if A(k,k) is NOT ZERO,
427* since that was ensured earlier in pivot search:
428* case A(k,k) = 0 falls into 2x2 pivot case(4))
429*
430 r1 = one / dble( a( k, k ) )
431 CALL zdscal( k-1, r1, a( 1, k ), 1 )
432*
433* (2) Conjugate column W(kw)
434*
435 CALL zlacgv( k-1, w( 1, kw ), 1 )
436 END IF
437*
438 ELSE
439*
440* 2-by-2 pivot block D(k): columns kw and kw-1 of W now hold
441*
442* ( W(kw-1) W(kw) ) = ( U(k-1) U(k) )*D(k)
443*
444* where U(k) and U(k-1) are the k-th and (k-1)-th columns
445* of U
446*
447* (1) Store U(1:k-2,k-1) and U(1:k-2,k) and 2-by-2
448* block D(k-1:k,k-1:k) in columns k-1 and k of A.
449* (NOTE: 2-by-2 diagonal block U(k-1:k,k-1:k) is a UNIT
450* block and not stored)
451* A(k-1:k,k-1:k) := D(k-1:k,k-1:k) = W(k-1:k,kw-1:kw)
452* A(1:k-2,k-1:k) := U(1:k-2,k:k-1:k) =
453* = W(1:k-2,kw-1:kw) * ( D(k-1:k,k-1:k)**(-1) )
454*
455 IF( k.GT.2 ) THEN
456*
457* Factor out the columns of the inverse of 2-by-2 pivot
458* block D, so that each column contains 1, to reduce the
459* number of FLOPS when we multiply panel
460* ( W(kw-1) W(kw) ) by this inverse, i.e. by D**(-1).
461*
462* D**(-1) = ( d11 cj(d21) )**(-1) =
463* ( d21 d22 )
464*
465* = 1/(d11*d22-|d21|**2) * ( ( d22) (-cj(d21) ) ) =
466* ( (-d21) ( d11 ) )
467*
468* = 1/(|d21|**2) * 1/((d11/cj(d21))*(d22/d21)-1) *
469*
470* * ( d21*( d22/d21 ) conj(d21)*( - 1 ) ) =
471* ( ( -1 ) ( d11/conj(d21) ) )
472*
473* = 1/(|d21|**2) * 1/(D22*D11-1) *
474*
475* * ( d21*( D11 ) conj(d21)*( -1 ) ) =
476* ( ( -1 ) ( D22 ) )
477*
478* = (1/|d21|**2) * T * ( d21*( D11 ) conj(d21)*( -1 ) ) =
479* ( ( -1 ) ( D22 ) )
480*
481* = ( (T/conj(d21))*( D11 ) (T/d21)*( -1 ) ) =
482* ( ( -1 ) ( D22 ) )
483*
484* = ( conj(D21)*( D11 ) D21*( -1 ) )
485* ( ( -1 ) ( D22 ) ),
486*
487* where D11 = d22/d21,
488* D22 = d11/conj(d21),
489* D21 = T/d21,
490* T = 1/(D22*D11-1).
491*
492* (NOTE: No need to check for division by ZERO,
493* since that was ensured earlier in pivot search:
494* (a) d21 != 0, since in 2x2 pivot case(4)
495* |d21| should be larger than |d11| and |d22|;
496* (b) (D22*D11 - 1) != 0, since from (a),
497* both |D11| < 1, |D22| < 1, hence |D22*D11| << 1.)
498*
499 d21 = w( k-1, kw )
500 d11 = w( k, kw ) / dconjg( d21 )
501 d22 = w( k-1, kw-1 ) / d21
502 t = one / ( dble( d11*d22 )-one )
503 d21 = t / d21
504*
505* Update elements in columns A(k-1) and A(k) as
506* dot products of rows of ( W(kw-1) W(kw) ) and columns
507* of D**(-1)
508*
509 DO 20 j = 1, k - 2
510 a( j, k-1 ) = d21*( d11*w( j, kw-1 )-w( j, kw ) )
511 a( j, k ) = dconjg( d21 )*
512 $ ( d22*w( j, kw )-w( j, kw-1 ) )
513 20 CONTINUE
514 END IF
515*
516* Copy D(k) to A
517*
518 a( k-1, k-1 ) = w( k-1, kw-1 )
519 a( k-1, k ) = w( k-1, kw )
520 a( k, k ) = w( k, kw )
521*
522* (2) Conjugate columns W(kw) and W(kw-1)
523*
524 CALL zlacgv( k-1, w( 1, kw ), 1 )
525 CALL zlacgv( k-2, w( 1, kw-1 ), 1 )
526*
527 END IF
528*
529 END IF
530*
531* Store details of the interchanges in IPIV
532*
533 IF( kstep.EQ.1 ) THEN
534 ipiv( k ) = kp
535 ELSE
536 ipiv( k ) = -kp
537 ipiv( k-1 ) = -kp
538 END IF
539*
540* Decrease K and return to the start of the main loop
541*
542 k = k - kstep
543 GO TO 10
544*
545 30 CONTINUE
546*
547* Update the upper triangle of A11 (= A(1:k,1:k)) as
548*
549* A11 := A11 - U12*D*U12**H = A11 - U12*W**H
550*
551* computing blocks of NB columns at a time (note that conjg(W) is
552* actually stored)
553*
554 DO 50 j = ( ( k-1 ) / nb )*nb + 1, 1, -nb
555 jb = min( nb, k-j+1 )
556*
557* Update the upper triangle of the diagonal block
558*
559 DO 40 jj = j, j + jb - 1
560 a( jj, jj ) = dble( a( jj, jj ) )
561 CALL zgemv( 'No transpose', jj-j+1, n-k, -cone,
562 $ a( j, k+1 ), lda, w( jj, kw+1 ), ldw, cone,
563 $ a( j, jj ), 1 )
564 a( jj, jj ) = dble( a( jj, jj ) )
565 40 CONTINUE
566*
567* Update the rectangular superdiagonal block
568*
569 CALL zgemm( 'No transpose', 'Transpose', j-1, jb, n-k,
570 $ -cone, a( 1, k+1 ), lda, w( j, kw+1 ), ldw,
571 $ cone, a( 1, j ), lda )
572 50 CONTINUE
573*
574* Put U12 in standard form by partially undoing the interchanges
575* in columns k+1:n looping backwards from k+1 to n
576*
577 j = k + 1
578 60 CONTINUE
579*
580* Undo the interchanges (if any) of rows JJ and JP at each
581* step J
582*
583* (Here, J is a diagonal index)
584 jj = j
585 jp = ipiv( j )
586 IF( jp.LT.0 ) THEN
587 jp = -jp
588* (Here, J is a diagonal index)
589 j = j + 1
590 END IF
591* (NOTE: Here, J is used to determine row length. Length N-J+1
592* of the rows to swap back doesn't include diagonal element)
593 j = j + 1
594 IF( jp.NE.jj .AND. j.LE.n )
595 $ CALL zswap( n-j+1, a( jp, j ), lda, a( jj, j ), lda )
596 IF( j.LT.n )
597 $ GO TO 60
598*
599* Set KB to the number of columns factorized
600*
601 kb = n - k
602*
603 ELSE
604*
605* Factorize the leading columns of A using the lower triangle
606* of A and working forwards, and compute the matrix W = L21*D
607* for use in updating A22 (note that conjg(W) is actually stored)
608*
609* K is the main loop index, increasing from 1 in steps of 1 or 2
610*
611 k = 1
612 70 CONTINUE
613*
614* Exit from loop
615*
616 IF( ( k.GE.nb .AND. nb.LT.n ) .OR. k.GT.n )
617 $ GO TO 90
618*
619 kstep = 1
620*
621* Copy column K of A to column K of W and update it
622*
623 w( k, k ) = dble( a( k, k ) )
624 IF( k.LT.n )
625 $ CALL zcopy( n-k, a( k+1, k ), 1, w( k+1, k ), 1 )
626 CALL zgemv( 'No transpose', n-k+1, k-1, -cone, a( k, 1 ), lda,
627 $ w( k, 1 ), ldw, cone, w( k, k ), 1 )
628 w( k, k ) = dble( w( k, k ) )
629*
630* Determine rows and columns to be interchanged and whether
631* a 1-by-1 or 2-by-2 pivot block will be used
632*
633 absakk = abs( dble( w( k, k ) ) )
634*
635* IMAX is the row-index of the largest off-diagonal element in
636* column K, and COLMAX is its absolute value.
637* Determine both COLMAX and IMAX.
638*
639 IF( k.LT.n ) THEN
640 imax = k + izamax( n-k, w( k+1, k ), 1 )
641 colmax = cabs1( w( imax, k ) )
642 ELSE
643 colmax = zero
644 END IF
645*
646 IF( max( absakk, colmax ).EQ.zero ) THEN
647*
648* Column K is zero or underflow: set INFO and continue
649*
650 IF( info.EQ.0 )
651 $ info = k
652 kp = k
653 a( k, k ) = dble( a( k, k ) )
654 ELSE
655*
656* ============================================================
657*
658* BEGIN pivot search
659*
660* Case(1)
661 IF( absakk.GE.alpha*colmax ) THEN
662*
663* no interchange, use 1-by-1 pivot block
664*
665 kp = k
666 ELSE
667*
668* BEGIN pivot search along IMAX row
669*
670*
671* Copy column IMAX to column K+1 of W and update it
672*
673 CALL zcopy( imax-k, a( imax, k ), lda, w( k, k+1 ), 1 )
674 CALL zlacgv( imax-k, w( k, k+1 ), 1 )
675 w( imax, k+1 ) = dble( a( imax, imax ) )
676 IF( imax.LT.n )
677 $ CALL zcopy( n-imax, a( imax+1, imax ), 1,
678 $ w( imax+1, k+1 ), 1 )
679 CALL zgemv( 'No transpose', n-k+1, k-1, -cone, a( k, 1 ),
680 $ lda, w( imax, 1 ), ldw, cone, w( k, k+1 ),
681 $ 1 )
682 w( imax, k+1 ) = dble( w( imax, k+1 ) )
683*
684* JMAX is the column-index of the largest off-diagonal
685* element in row IMAX, and ROWMAX is its absolute value.
686* Determine only ROWMAX.
687*
688 jmax = k - 1 + izamax( imax-k, w( k, k+1 ), 1 )
689 rowmax = cabs1( w( jmax, k+1 ) )
690 IF( imax.LT.n ) THEN
691 jmax = imax + izamax( n-imax, w( imax+1, k+1 ), 1 )
692 rowmax = max( rowmax, cabs1( w( jmax, k+1 ) ) )
693 END IF
694*
695* Case(2)
696 IF( absakk.GE.alpha*colmax*( colmax / rowmax ) ) THEN
697*
698* no interchange, use 1-by-1 pivot block
699*
700 kp = k
701*
702* Case(3)
703 ELSE IF( abs( dble( w( imax, k+1 ) ) ).GE.alpha*rowmax )
704 $ THEN
705*
706* interchange rows and columns K and IMAX, use 1-by-1
707* pivot block
708*
709 kp = imax
710*
711* copy column K+1 of W to column K of W
712*
713 CALL zcopy( n-k+1, w( k, k+1 ), 1, w( k, k ), 1 )
714*
715* Case(4)
716 ELSE
717*
718* interchange rows and columns K+1 and IMAX, use 2-by-2
719* pivot block
720*
721 kp = imax
722 kstep = 2
723 END IF
724*
725*
726* END pivot search along IMAX row
727*
728 END IF
729*
730* END pivot search
731*
732* ============================================================
733*
734* KK is the column of A where pivoting step stopped
735*
736 kk = k + kstep - 1
737*
738* Interchange rows and columns KP and KK.
739* Updated column KP is already stored in column KK of W.
740*
741 IF( kp.NE.kk ) THEN
742*
743* Copy non-updated column KK to column KP of submatrix A
744* at step K. No need to copy element into column K
745* (or K and K+1 for 2-by-2 pivot) of A, since these columns
746* will be later overwritten.
747*
748 a( kp, kp ) = dble( a( kk, kk ) )
749 CALL zcopy( kp-kk-1, a( kk+1, kk ), 1, a( kp, kk+1 ),
750 $ lda )
751 CALL zlacgv( kp-kk-1, a( kp, kk+1 ), lda )
752 IF( kp.LT.n )
753 $ CALL zcopy( n-kp, a( kp+1, kk ), 1, a( kp+1, kp ), 1 )
754*
755* Interchange rows KK and KP in first K-1 columns of A
756* (columns K (or K and K+1 for 2-by-2 pivot) of A will be
757* later overwritten). Interchange rows KK and KP
758* in first KK columns of W.
759*
760 IF( k.GT.1 )
761 $ CALL zswap( k-1, a( kk, 1 ), lda, a( kp, 1 ), lda )
762 CALL zswap( kk, w( kk, 1 ), ldw, w( kp, 1 ), ldw )
763 END IF
764*
765 IF( kstep.EQ.1 ) THEN
766*
767* 1-by-1 pivot block D(k): column k of W now holds
768*
769* W(k) = L(k)*D(k),
770*
771* where L(k) is the k-th column of L
772*
773* (1) Store subdiag. elements of column L(k)
774* and 1-by-1 block D(k) in column k of A.
775* (NOTE: Diagonal element L(k,k) is a UNIT element
776* and not stored)
777* A(k,k) := D(k,k) = W(k,k)
778* A(k+1:N,k) := L(k+1:N,k) = W(k+1:N,k)/D(k,k)
779*
780* (NOTE: No need to use for Hermitian matrix
781* A( K, K ) = DBLE( W( K, K) ) to separately copy diagonal
782* element D(k,k) from W (potentially saves only one load))
783 CALL zcopy( n-k+1, w( k, k ), 1, a( k, k ), 1 )
784 IF( k.LT.n ) THEN
785*
786* (NOTE: No need to check if A(k,k) is NOT ZERO,
787* since that was ensured earlier in pivot search:
788* case A(k,k) = 0 falls into 2x2 pivot case(4))
789*
790 r1 = one / dble( a( k, k ) )
791 CALL zdscal( n-k, r1, a( k+1, k ), 1 )
792*
793* (2) Conjugate column W(k)
794*
795 CALL zlacgv( n-k, w( k+1, k ), 1 )
796 END IF
797*
798 ELSE
799*
800* 2-by-2 pivot block D(k): columns k and k+1 of W now hold
801*
802* ( W(k) W(k+1) ) = ( L(k) L(k+1) )*D(k)
803*
804* where L(k) and L(k+1) are the k-th and (k+1)-th columns
805* of L
806*
807* (1) Store L(k+2:N,k) and L(k+2:N,k+1) and 2-by-2
808* block D(k:k+1,k:k+1) in columns k and k+1 of A.
809* (NOTE: 2-by-2 diagonal block L(k:k+1,k:k+1) is a UNIT
810* block and not stored)
811* A(k:k+1,k:k+1) := D(k:k+1,k:k+1) = W(k:k+1,k:k+1)
812* A(k+2:N,k:k+1) := L(k+2:N,k:k+1) =
813* = W(k+2:N,k:k+1) * ( D(k:k+1,k:k+1)**(-1) )
814*
815 IF( k.LT.n-1 ) THEN
816*
817* Factor out the columns of the inverse of 2-by-2 pivot
818* block D, so that each column contains 1, to reduce the
819* number of FLOPS when we multiply panel
820* ( W(kw-1) W(kw) ) by this inverse, i.e. by D**(-1).
821*
822* D**(-1) = ( d11 cj(d21) )**(-1) =
823* ( d21 d22 )
824*
825* = 1/(d11*d22-|d21|**2) * ( ( d22) (-cj(d21) ) ) =
826* ( (-d21) ( d11 ) )
827*
828* = 1/(|d21|**2) * 1/((d11/cj(d21))*(d22/d21)-1) *
829*
830* * ( d21*( d22/d21 ) conj(d21)*( - 1 ) ) =
831* ( ( -1 ) ( d11/conj(d21) ) )
832*
833* = 1/(|d21|**2) * 1/(D22*D11-1) *
834*
835* * ( d21*( D11 ) conj(d21)*( -1 ) ) =
836* ( ( -1 ) ( D22 ) )
837*
838* = (1/|d21|**2) * T * ( d21*( D11 ) conj(d21)*( -1 ) ) =
839* ( ( -1 ) ( D22 ) )
840*
841* = ( (T/conj(d21))*( D11 ) (T/d21)*( -1 ) ) =
842* ( ( -1 ) ( D22 ) )
843*
844* = ( conj(D21)*( D11 ) D21*( -1 ) )
845* ( ( -1 ) ( D22 ) ),
846*
847* where D11 = d22/d21,
848* D22 = d11/conj(d21),
849* D21 = T/d21,
850* T = 1/(D22*D11-1).
851*
852* (NOTE: No need to check for division by ZERO,
853* since that was ensured earlier in pivot search:
854* (a) d21 != 0, since in 2x2 pivot case(4)
855* |d21| should be larger than |d11| and |d22|;
856* (b) (D22*D11 - 1) != 0, since from (a),
857* both |D11| < 1, |D22| < 1, hence |D22*D11| << 1.)
858*
859 d21 = w( k+1, k )
860 d11 = w( k+1, k+1 ) / d21
861 d22 = w( k, k ) / dconjg( d21 )
862 t = one / ( dble( d11*d22 )-one )
863 d21 = t / d21
864*
865* Update elements in columns A(k) and A(k+1) as
866* dot products of rows of ( W(k) W(k+1) ) and columns
867* of D**(-1)
868*
869 DO 80 j = k + 2, n
870 a( j, k ) = dconjg( d21 )*
871 $ ( d11*w( j, k )-w( j, k+1 ) )
872 a( j, k+1 ) = d21*( d22*w( j, k+1 )-w( j, k ) )
873 80 CONTINUE
874 END IF
875*
876* Copy D(k) to A
877*
878 a( k, k ) = w( k, k )
879 a( k+1, k ) = w( k+1, k )
880 a( k+1, k+1 ) = w( k+1, k+1 )
881*
882* (2) Conjugate columns W(k) and W(k+1)
883*
884 CALL zlacgv( n-k, w( k+1, k ), 1 )
885 CALL zlacgv( n-k-1, w( k+2, k+1 ), 1 )
886*
887 END IF
888*
889 END IF
890*
891* Store details of the interchanges in IPIV
892*
893 IF( kstep.EQ.1 ) THEN
894 ipiv( k ) = kp
895 ELSE
896 ipiv( k ) = -kp
897 ipiv( k+1 ) = -kp
898 END IF
899*
900* Increase K and return to the start of the main loop
901*
902 k = k + kstep
903 GO TO 70
904*
905 90 CONTINUE
906*
907* Update the lower triangle of A22 (= A(k:n,k:n)) as
908*
909* A22 := A22 - L21*D*L21**H = A22 - L21*W**H
910*
911* computing blocks of NB columns at a time (note that conjg(W) is
912* actually stored)
913*
914 DO 110 j = k, n, nb
915 jb = min( nb, n-j+1 )
916*
917* Update the lower triangle of the diagonal block
918*
919 DO 100 jj = j, j + jb - 1
920 a( jj, jj ) = dble( a( jj, jj ) )
921 CALL zgemv( 'No transpose', j+jb-jj, k-1, -cone,
922 $ a( jj, 1 ), lda, w( jj, 1 ), ldw, cone,
923 $ a( jj, jj ), 1 )
924 a( jj, jj ) = dble( a( jj, jj ) )
925 100 CONTINUE
926*
927* Update the rectangular subdiagonal block
928*
929 IF( j+jb.LE.n )
930 $ CALL zgemm( 'No transpose', 'Transpose', n-j-jb+1, jb,
931 $ k-1, -cone, a( j+jb, 1 ), lda, w( j, 1 ),
932 $ ldw, cone, a( j+jb, j ), lda )
933 110 CONTINUE
934*
935* Put L21 in standard form by partially undoing the interchanges
936* of rows in columns 1:k-1 looping backwards from k-1 to 1
937*
938 j = k - 1
939 120 CONTINUE
940*
941* Undo the interchanges (if any) of rows JJ and JP at each
942* step J
943*
944* (Here, J is a diagonal index)
945 jj = j
946 jp = ipiv( j )
947 IF( jp.LT.0 ) THEN
948 jp = -jp
949* (Here, J is a diagonal index)
950 j = j - 1
951 END IF
952* (NOTE: Here, J is used to determine row length. Length J
953* of the rows to swap back doesn't include diagonal element)
954 j = j - 1
955 IF( jp.NE.jj .AND. j.GE.1 )
956 $ CALL zswap( j, a( jp, 1 ), lda, a( jj, 1 ), lda )
957 IF( j.GT.1 )
958 $ GO TO 120
959*
960* Set KB to the number of columns factorized
961*
962 kb = k - 1
963*
964 END IF
965 RETURN
966*
967* End of ZLAHEF
968*
969 END
subroutine zcopy(n, zx, incx, zy, incy)
ZCOPY
Definition zcopy.f:81
subroutine zgemm(transa, transb, m, n, k, alpha, a, lda, b, ldb, beta, c, ldc)
ZGEMM
Definition zgemm.f:188
subroutine zgemv(trans, m, n, alpha, a, lda, x, incx, beta, y, incy)
ZGEMV
Definition zgemv.f:160
subroutine zlacgv(n, x, incx)
ZLACGV conjugates a complex vector.
Definition zlacgv.f:74
subroutine zlahef(uplo, n, nb, kb, a, lda, ipiv, w, ldw, info)
ZLAHEF computes a partial factorization of a complex Hermitian indefinite matrix using the Bunch-Kauf...
Definition zlahef.f:177
subroutine zdscal(n, da, zx, incx)
ZDSCAL
Definition zdscal.f:78
subroutine zswap(n, zx, incx, zy, incy)
ZSWAP
Definition zswap.f:81