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