You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

zlahef_rook.f 40 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176
  1. * \brief \b ZLAHEF_ROOK computes a partial factorization of a complex Hermitian indefinite matrix using the bounded Bunch-Kaufman ("rook") 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_ROOK + dependencies
  10. *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/zlahef_rook.f">
  11. *> [TGZ]</a>
  12. *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/zlahef_rook.f">
  13. *> [ZIP]</a>
  14. *> <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/zlahef_rook.f">
  15. *> [TXT]</a>
  16. *> \endhtmlonly
  17. *
  18. * Definition:
  19. * ===========
  20. *
  21. * SUBROUTINE ZLAHEF_ROOK( 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_ROOK computes a partial factorization of a complex Hermitian
  39. *> matrix A using the bounded Bunch-Kaufman ("rook") diagonal pivoting
  40. *> method. The 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_ROOK is an auxiliary routine called by ZHETRF_ROOK. It uses
  53. *> blocked code (calling Level 3 BLAS) to update the submatrix
  54. *> A11 (if UPLO = 'U') or 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) < 0 and IPIV(k-1) < 0, then rows and
  121. *> columns k and -IPIV(k) were interchanged and rows and
  122. *> columns k-1 and -IPIV(k-1) were inerchaged,
  123. *> D(k-1:k,k-1:k) is a 2-by-2 diagonal block.
  124. *>
  125. *> If UPLO = 'L':
  126. *> Only the first KB elements of IPIV are set.
  127. *>
  128. *> If IPIV(k) > 0, then rows and columns k and IPIV(k)
  129. *> were interchanged and D(k,k) is a 1-by-1 diagonal block.
  130. *>
  131. *> If IPIV(k) < 0 and IPIV(k+1) < 0, then rows and
  132. *> columns k and -IPIV(k) were interchanged and rows and
  133. *> columns k+1 and -IPIV(k+1) were inerchaged,
  134. *> D(k:k+1,k:k+1) is a 2-by-2 diagonal block.
  135. *> \endverbatim
  136. *>
  137. *> \param[out] W
  138. *> \verbatim
  139. *> W is COMPLEX*16 array, dimension (LDW,NB)
  140. *> \endverbatim
  141. *>
  142. *> \param[in] LDW
  143. *> \verbatim
  144. *> LDW is INTEGER
  145. *> The leading dimension of the array W. LDW >= max(1,N).
  146. *> \endverbatim
  147. *>
  148. *> \param[out] INFO
  149. *> \verbatim
  150. *> INFO is INTEGER
  151. *> = 0: successful exit
  152. *> > 0: if INFO = k, D(k,k) is exactly zero. The factorization
  153. *> has been completed, but the block diagonal matrix D is
  154. *> exactly singular.
  155. *> \endverbatim
  156. *
  157. * Authors:
  158. * ========
  159. *
  160. *> \author Univ. of Tennessee
  161. *> \author Univ. of California Berkeley
  162. *> \author Univ. of Colorado Denver
  163. *> \author NAG Ltd.
  164. *
  165. *> \date November 2013
  166. *
  167. *> \ingroup complex16HEcomputational
  168. *
  169. *> \par Contributors:
  170. * ==================
  171. *>
  172. *> \verbatim
  173. *>
  174. *> November 2013, Igor Kozachenko,
  175. *> Computer Science Division,
  176. *> University of California, Berkeley
  177. *>
  178. *> September 2007, Sven Hammarling, Nicholas J. Higham, Craig Lucas,
  179. *> School of Mathematics,
  180. *> University of Manchester
  181. *> \endverbatim
  182. *
  183. * =====================================================================
  184. SUBROUTINE ZLAHEF_ROOK( UPLO, N, NB, KB, A, LDA, IPIV, W, LDW,
  185. $ INFO )
  186. *
  187. * -- LAPACK computational routine (version 3.5.0) --
  188. * -- LAPACK is a software package provided by Univ. of Tennessee, --
  189. * -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--
  190. * November 2013
  191. *
  192. * .. Scalar Arguments ..
  193. CHARACTER UPLO
  194. INTEGER INFO, KB, LDA, LDW, N, NB
  195. * ..
  196. * .. Array Arguments ..
  197. INTEGER IPIV( * )
  198. COMPLEX*16 A( LDA, * ), W( LDW, * )
  199. * ..
  200. *
  201. * =====================================================================
  202. *
  203. * .. Parameters ..
  204. DOUBLE PRECISION ZERO, ONE
  205. PARAMETER ( ZERO = 0.0D+0, ONE = 1.0D+0 )
  206. COMPLEX*16 CONE
  207. PARAMETER ( CONE = ( 1.0D+0, 0.0D+0 ) )
  208. DOUBLE PRECISION EIGHT, SEVTEN
  209. PARAMETER ( EIGHT = 8.0D+0, SEVTEN = 17.0D+0 )
  210. * ..
  211. * .. Local Scalars ..
  212. LOGICAL DONE
  213. INTEGER IMAX, ITEMP, II, J, JB, JJ, JMAX, JP1, JP2, K,
  214. $ KK, KKW, KP, KSTEP, KW, P
  215. DOUBLE PRECISION ABSAKK, ALPHA, COLMAX, DTEMP, R1, ROWMAX, T,
  216. $ SFMIN
  217. COMPLEX*16 D11, D21, D22, Z
  218. * ..
  219. * .. External Functions ..
  220. LOGICAL LSAME
  221. INTEGER IZAMAX
  222. DOUBLE PRECISION DLAMCH
  223. EXTERNAL LSAME, IZAMAX, DLAMCH
  224. * ..
  225. * .. External Subroutines ..
  226. EXTERNAL ZCOPY, ZDSCAL, ZGEMM, ZGEMV, ZLACGV, ZSWAP
  227. * ..
  228. * .. Intrinsic Functions ..
  229. INTRINSIC ABS, DBLE, DCONJG, DIMAG, MAX, MIN, SQRT
  230. * ..
  231. * .. Statement Functions ..
  232. DOUBLE PRECISION CABS1
  233. * ..
  234. * .. Statement Function definitions ..
  235. CABS1( Z ) = ABS( DBLE( Z ) ) + ABS( DIMAG( Z ) )
  236. * ..
  237. * .. Executable Statements ..
  238. *
  239. INFO = 0
  240. *
  241. * Initialize ALPHA for use in choosing pivot block size.
  242. *
  243. ALPHA = ( ONE+SQRT( SEVTEN ) ) / EIGHT
  244. *
  245. * Compute machine safe minimum
  246. *
  247. SFMIN = DLAMCH( 'S' )
  248. *
  249. IF( LSAME( UPLO, 'U' ) ) THEN
  250. *
  251. * Factorize the trailing columns of A using the upper triangle
  252. * of A and working backwards, and compute the matrix W = U12*D
  253. * for use in updating A11 (note that conjg(W) is actually stored)
  254. *
  255. * K is the main loop index, decreasing from N in steps of 1 or 2
  256. *
  257. K = N
  258. 10 CONTINUE
  259. *
  260. * KW is the column of W which corresponds to column K of A
  261. *
  262. KW = NB + K - N
  263. *
  264. * Exit from loop
  265. *
  266. IF( ( K.LE.N-NB+1 .AND. NB.LT.N ) .OR. K.LT.1 )
  267. $ GO TO 30
  268. *
  269. KSTEP = 1
  270. P = K
  271. *
  272. * Copy column K of A to column KW of W and update it
  273. *
  274. IF( K.GT.1 )
  275. $ CALL ZCOPY( K-1, A( 1, K ), 1, W( 1, KW ), 1 )
  276. W( K, KW ) = DBLE( A( K, K ) )
  277. IF( K.LT.N ) THEN
  278. CALL ZGEMV( 'No transpose', K, N-K, -CONE, A( 1, K+1 ), LDA,
  279. $ W( K, KW+1 ), LDW, CONE, W( 1, KW ), 1 )
  280. W( K, KW ) = DBLE( W( K, KW ) )
  281. END IF
  282. *
  283. * Determine rows and columns to be interchanged and whether
  284. * a 1-by-1 or 2-by-2 pivot block will be used
  285. *
  286. ABSAKK = ABS( DBLE( W( K, KW ) ) )
  287. *
  288. * IMAX is the row-index of the largest off-diagonal element in
  289. * column K, and COLMAX is its absolute value.
  290. * Determine both COLMAX and IMAX.
  291. *
  292. IF( K.GT.1 ) THEN
  293. IMAX = IZAMAX( K-1, W( 1, KW ), 1 )
  294. COLMAX = CABS1( W( IMAX, KW ) )
  295. ELSE
  296. COLMAX = ZERO
  297. END IF
  298. *
  299. IF( MAX( ABSAKK, COLMAX ).EQ.ZERO ) THEN
  300. *
  301. * Column K is zero or underflow: set INFO and continue
  302. *
  303. IF( INFO.EQ.0 )
  304. $ INFO = K
  305. KP = K
  306. A( K, K ) = DBLE( W( K, KW ) )
  307. IF( K.GT.1 )
  308. $ CALL ZCOPY( K-1, W( 1, KW ), 1, A( 1, K ), 1 )
  309. ELSE
  310. *
  311. * ============================================================
  312. *
  313. * BEGIN pivot search
  314. *
  315. * Case(1)
  316. * Equivalent to testing for ABSAKK.GE.ALPHA*COLMAX
  317. * (used to handle NaN and Inf)
  318. IF( .NOT.( ABSAKK.LT.ALPHA*COLMAX ) ) THEN
  319. *
  320. * no interchange, use 1-by-1 pivot block
  321. *
  322. KP = K
  323. *
  324. ELSE
  325. *
  326. * Lop until pivot found
  327. *
  328. DONE = .FALSE.
  329. *
  330. 12 CONTINUE
  331. *
  332. * BEGIN pivot search loop body
  333. *
  334. *
  335. * Copy column IMAX to column KW-1 of W and update it
  336. *
  337. IF( IMAX.GT.1 )
  338. $ CALL ZCOPY( IMAX-1, A( 1, IMAX ), 1, W( 1, KW-1 ),
  339. $ 1 )
  340. W( IMAX, KW-1 ) = DBLE( A( IMAX, IMAX ) )
  341. *
  342. CALL ZCOPY( K-IMAX, A( IMAX, IMAX+1 ), LDA,
  343. $ W( IMAX+1, KW-1 ), 1 )
  344. CALL ZLACGV( K-IMAX, W( IMAX+1, KW-1 ), 1 )
  345. *
  346. IF( K.LT.N ) THEN
  347. CALL ZGEMV( 'No transpose', K, N-K, -CONE,
  348. $ A( 1, K+1 ), LDA, W( IMAX, KW+1 ), LDW,
  349. $ CONE, W( 1, KW-1 ), 1 )
  350. W( IMAX, KW-1 ) = DBLE( W( IMAX, KW-1 ) )
  351. END IF
  352. *
  353. * JMAX is the column-index of the largest off-diagonal
  354. * element in row IMAX, and ROWMAX is its absolute value.
  355. * Determine both ROWMAX and JMAX.
  356. *
  357. IF( IMAX.NE.K ) THEN
  358. JMAX = IMAX + IZAMAX( K-IMAX, W( IMAX+1, KW-1 ),
  359. $ 1 )
  360. ROWMAX = CABS1( W( JMAX, KW-1 ) )
  361. ELSE
  362. ROWMAX = ZERO
  363. END IF
  364. *
  365. IF( IMAX.GT.1 ) THEN
  366. ITEMP = IZAMAX( IMAX-1, W( 1, KW-1 ), 1 )
  367. DTEMP = CABS1( W( ITEMP, KW-1 ) )
  368. IF( DTEMP.GT.ROWMAX ) THEN
  369. ROWMAX = DTEMP
  370. JMAX = ITEMP
  371. END IF
  372. END IF
  373. *
  374. * Case(2)
  375. * Equivalent to testing for
  376. * ABS( REAL( W( IMAX,KW-1 ) ) ).GE.ALPHA*ROWMAX
  377. * (used to handle NaN and Inf)
  378. *
  379. IF( .NOT.( ABS( DBLE( W( IMAX,KW-1 ) ) )
  380. $ .LT.ALPHA*ROWMAX ) ) THEN
  381. *
  382. * interchange rows and columns K and IMAX,
  383. * use 1-by-1 pivot block
  384. *
  385. KP = IMAX
  386. *
  387. * copy column KW-1 of W to column KW of W
  388. *
  389. CALL ZCOPY( K, W( 1, KW-1 ), 1, W( 1, KW ), 1 )
  390. *
  391. DONE = .TRUE.
  392. *
  393. * Case(3)
  394. * Equivalent to testing for ROWMAX.EQ.COLMAX,
  395. * (used to handle NaN and Inf)
  396. *
  397. ELSE IF( ( P.EQ.JMAX ) .OR. ( ROWMAX.LE.COLMAX ) )
  398. $ THEN
  399. *
  400. * interchange rows and columns K-1 and IMAX,
  401. * use 2-by-2 pivot block
  402. *
  403. KP = IMAX
  404. KSTEP = 2
  405. DONE = .TRUE.
  406. *
  407. * Case(4)
  408. ELSE
  409. *
  410. * Pivot not found: set params and repeat
  411. *
  412. P = IMAX
  413. COLMAX = ROWMAX
  414. IMAX = JMAX
  415. *
  416. * Copy updated JMAXth (next IMAXth) column to Kth of W
  417. *
  418. CALL ZCOPY( K, W( 1, KW-1 ), 1, W( 1, KW ), 1 )
  419. *
  420. END IF
  421. *
  422. *
  423. * END pivot search loop body
  424. *
  425. IF( .NOT.DONE ) GOTO 12
  426. *
  427. END IF
  428. *
  429. * END pivot search
  430. *
  431. * ============================================================
  432. *
  433. * KK is the column of A where pivoting step stopped
  434. *
  435. KK = K - KSTEP + 1
  436. *
  437. * KKW is the column of W which corresponds to column KK of A
  438. *
  439. KKW = NB + KK - N
  440. *
  441. * Interchange rows and columns P and K.
  442. * Updated column P is already stored in column KW of W.
  443. *
  444. IF( ( KSTEP.EQ.2 ) .AND. ( P.NE.K ) ) THEN
  445. *
  446. * Copy non-updated column K to column P of submatrix A
  447. * at step K. No need to copy element into columns
  448. * K and K-1 of A for 2-by-2 pivot, since these columns
  449. * will be later overwritten.
  450. *
  451. A( P, P ) = DBLE( A( K, K ) )
  452. CALL ZCOPY( K-1-P, A( P+1, K ), 1, A( P, P+1 ),
  453. $ LDA )
  454. CALL ZLACGV( K-1-P, A( P, P+1 ), LDA )
  455. IF( P.GT.1 )
  456. $ CALL ZCOPY( P-1, A( 1, K ), 1, A( 1, P ), 1 )
  457. *
  458. * Interchange rows K and P in the last K+1 to N columns of A
  459. * (columns K and K-1 of A for 2-by-2 pivot will be
  460. * later overwritten). Interchange rows K and P
  461. * in last KKW to NB columns of W.
  462. *
  463. IF( K.LT.N )
  464. $ CALL ZSWAP( N-K, A( K, K+1 ), LDA, A( P, K+1 ),
  465. $ LDA )
  466. CALL ZSWAP( N-KK+1, W( K, KKW ), LDW, W( P, KKW ),
  467. $ LDW )
  468. END IF
  469. *
  470. * Interchange rows and columns KP and KK.
  471. * Updated column KP is already stored in column KKW of W.
  472. *
  473. IF( KP.NE.KK ) THEN
  474. *
  475. * Copy non-updated column KK to column KP of submatrix A
  476. * at step K. No need to copy element into column K
  477. * (or K and K-1 for 2-by-2 pivot) of A, since these columns
  478. * will be later overwritten.
  479. *
  480. A( KP, KP ) = DBLE( A( KK, KK ) )
  481. CALL ZCOPY( KK-1-KP, A( KP+1, KK ), 1, A( KP, KP+1 ),
  482. $ LDA )
  483. CALL ZLACGV( KK-1-KP, A( KP, KP+1 ), LDA )
  484. IF( KP.GT.1 )
  485. $ CALL ZCOPY( KP-1, A( 1, KK ), 1, A( 1, KP ), 1 )
  486. *
  487. * Interchange rows KK and KP in last K+1 to N columns of A
  488. * (columns K (or K and K-1 for 2-by-2 pivot) of A will be
  489. * later overwritten). Interchange rows KK and KP
  490. * in last KKW to NB columns of W.
  491. *
  492. IF( K.LT.N )
  493. $ CALL ZSWAP( N-K, A( KK, K+1 ), LDA, A( KP, K+1 ),
  494. $ LDA )
  495. CALL ZSWAP( N-KK+1, W( KK, KKW ), LDW, W( KP, KKW ),
  496. $ LDW )
  497. END IF
  498. *
  499. IF( KSTEP.EQ.1 ) THEN
  500. *
  501. * 1-by-1 pivot block D(k): column kw of W now holds
  502. *
  503. * W(kw) = U(k)*D(k),
  504. *
  505. * where U(k) is the k-th column of U
  506. *
  507. * (1) Store subdiag. elements of column U(k)
  508. * and 1-by-1 block D(k) in column k of A.
  509. * (NOTE: Diagonal element U(k,k) is a UNIT element
  510. * and not stored)
  511. * A(k,k) := D(k,k) = W(k,kw)
  512. * A(1:k-1,k) := U(1:k-1,k) = W(1:k-1,kw)/D(k,k)
  513. *
  514. * (NOTE: No need to use for Hermitian matrix
  515. * A( K, K ) = REAL( W( K, K) ) to separately copy diagonal
  516. * element D(k,k) from W (potentially saves only one load))
  517. CALL ZCOPY( K, W( 1, KW ), 1, A( 1, K ), 1 )
  518. IF( K.GT.1 ) THEN
  519. *
  520. * (NOTE: No need to check if A(k,k) is NOT ZERO,
  521. * since that was ensured earlier in pivot search:
  522. * case A(k,k) = 0 falls into 2x2 pivot case(3))
  523. *
  524. * Handle division by a small number
  525. *
  526. T = DBLE( A( K, K ) )
  527. IF( ABS( T ).GE.SFMIN ) THEN
  528. R1 = ONE / T
  529. CALL ZDSCAL( K-1, R1, A( 1, K ), 1 )
  530. ELSE
  531. DO 14 II = 1, K-1
  532. A( II, K ) = A( II, K ) / T
  533. 14 CONTINUE
  534. END IF
  535. *
  536. * (2) Conjugate column W(kw)
  537. *
  538. CALL ZLACGV( K-1, W( 1, KW ), 1 )
  539. END IF
  540. *
  541. ELSE
  542. *
  543. * 2-by-2 pivot block D(k): columns kw and kw-1 of W now hold
  544. *
  545. * ( W(kw-1) W(kw) ) = ( U(k-1) U(k) )*D(k)
  546. *
  547. * where U(k) and U(k-1) are the k-th and (k-1)-th columns
  548. * of U
  549. *
  550. * (1) Store U(1:k-2,k-1) and U(1:k-2,k) and 2-by-2
  551. * block D(k-1:k,k-1:k) in columns k-1 and k of A.
  552. * (NOTE: 2-by-2 diagonal block U(k-1:k,k-1:k) is a UNIT
  553. * block and not stored)
  554. * A(k-1:k,k-1:k) := D(k-1:k,k-1:k) = W(k-1:k,kw-1:kw)
  555. * A(1:k-2,k-1:k) := U(1:k-2,k:k-1:k) =
  556. * = W(1:k-2,kw-1:kw) * ( D(k-1:k,k-1:k)**(-1) )
  557. *
  558. IF( K.GT.2 ) THEN
  559. *
  560. * Factor out the columns of the inverse of 2-by-2 pivot
  561. * block D, so that each column contains 1, to reduce the
  562. * number of FLOPS when we multiply panel
  563. * ( W(kw-1) W(kw) ) by this inverse, i.e. by D**(-1).
  564. *
  565. * D**(-1) = ( d11 cj(d21) )**(-1) =
  566. * ( d21 d22 )
  567. *
  568. * = 1/(d11*d22-|d21|**2) * ( ( d22) (-cj(d21) ) ) =
  569. * ( (-d21) ( d11 ) )
  570. *
  571. * = 1/(|d21|**2) * 1/((d11/cj(d21))*(d22/d21)-1) *
  572. *
  573. * * ( d21*( d22/d21 ) conj(d21)*( - 1 ) ) =
  574. * ( ( -1 ) ( d11/conj(d21) ) )
  575. *
  576. * = 1/(|d21|**2) * 1/(D22*D11-1) *
  577. *
  578. * * ( d21*( D11 ) conj(d21)*( -1 ) ) =
  579. * ( ( -1 ) ( D22 ) )
  580. *
  581. * = (1/|d21|**2) * T * ( d21*( D11 ) conj(d21)*( -1 ) ) =
  582. * ( ( -1 ) ( D22 ) )
  583. *
  584. * = ( (T/conj(d21))*( D11 ) (T/d21)*( -1 ) ) =
  585. * ( ( -1 ) ( D22 ) )
  586. *
  587. * Handle division by a small number. (NOTE: order of
  588. * operations is important)
  589. *
  590. * = ( T*(( D11 )/conj(D21)) T*(( -1 )/D21 ) )
  591. * ( (( -1 ) ) (( D22 ) ) ),
  592. *
  593. * where D11 = d22/d21,
  594. * D22 = d11/conj(d21),
  595. * D21 = d21,
  596. * T = 1/(D22*D11-1).
  597. *
  598. * (NOTE: No need to check for division by ZERO,
  599. * since that was ensured earlier in pivot search:
  600. * (a) d21 != 0 in 2x2 pivot case(4),
  601. * since |d21| should be larger than |d11| and |d22|;
  602. * (b) (D22*D11 - 1) != 0, since from (a),
  603. * both |D11| < 1, |D22| < 1, hence |D22*D11| << 1.)
  604. *
  605. D21 = W( K-1, KW )
  606. D11 = W( K, KW ) / DCONJG( D21 )
  607. D22 = W( K-1, KW-1 ) / D21
  608. T = ONE / ( DBLE( D11*D22 )-ONE )
  609. *
  610. * Update elements in columns A(k-1) and A(k) as
  611. * dot products of rows of ( W(kw-1) W(kw) ) and columns
  612. * of D**(-1)
  613. *
  614. DO 20 J = 1, K - 2
  615. A( J, K-1 ) = T*( ( D11*W( J, KW-1 )-W( J, KW ) ) /
  616. $ D21 )
  617. A( J, K ) = T*( ( D22*W( J, KW )-W( J, KW-1 ) ) /
  618. $ DCONJG( D21 ) )
  619. 20 CONTINUE
  620. END IF
  621. *
  622. * Copy D(k) to A
  623. *
  624. A( K-1, K-1 ) = W( K-1, KW-1 )
  625. A( K-1, K ) = W( K-1, KW )
  626. A( K, K ) = W( K, KW )
  627. *
  628. * (2) Conjugate columns W(kw) and W(kw-1)
  629. *
  630. CALL ZLACGV( K-1, W( 1, KW ), 1 )
  631. CALL ZLACGV( K-2, W( 1, KW-1 ), 1 )
  632. *
  633. END IF
  634. *
  635. END IF
  636. *
  637. * Store details of the interchanges in IPIV
  638. *
  639. IF( KSTEP.EQ.1 ) THEN
  640. IPIV( K ) = KP
  641. ELSE
  642. IPIV( K ) = -P
  643. IPIV( K-1 ) = -KP
  644. END IF
  645. *
  646. * Decrease K and return to the start of the main loop
  647. *
  648. K = K - KSTEP
  649. GO TO 10
  650. *
  651. 30 CONTINUE
  652. *
  653. * Update the upper triangle of A11 (= A(1:k,1:k)) as
  654. *
  655. * A11 := A11 - U12*D*U12**H = A11 - U12*W**H
  656. *
  657. * computing blocks of NB columns at a time (note that conjg(W) is
  658. * actually stored)
  659. *
  660. DO 50 J = ( ( K-1 ) / NB )*NB + 1, 1, -NB
  661. JB = MIN( NB, K-J+1 )
  662. *
  663. * Update the upper triangle of the diagonal block
  664. *
  665. DO 40 JJ = J, J + JB - 1
  666. A( JJ, JJ ) = DBLE( A( JJ, JJ ) )
  667. CALL ZGEMV( 'No transpose', JJ-J+1, N-K, -CONE,
  668. $ A( J, K+1 ), LDA, W( JJ, KW+1 ), LDW, CONE,
  669. $ A( J, JJ ), 1 )
  670. A( JJ, JJ ) = DBLE( A( JJ, JJ ) )
  671. 40 CONTINUE
  672. *
  673. * Update the rectangular superdiagonal block
  674. *
  675. IF( J.GE.2 )
  676. $ CALL ZGEMM( 'No transpose', 'Transpose', J-1, JB, N-K,
  677. $ -CONE, A( 1, K+1 ), LDA, W( J, KW+1 ), LDW,
  678. $ CONE, A( 1, J ), LDA )
  679. 50 CONTINUE
  680. *
  681. * Put U12 in standard form by partially undoing the interchanges
  682. * in of rows in columns k+1:n looping backwards from k+1 to n
  683. *
  684. J = K + 1
  685. 60 CONTINUE
  686. *
  687. * Undo the interchanges (if any) of rows J and JP2
  688. * (or J and JP2, and J+1 and JP1) at each step J
  689. *
  690. KSTEP = 1
  691. JP1 = 1
  692. * (Here, J is a diagonal index)
  693. JJ = J
  694. JP2 = IPIV( J )
  695. IF( JP2.LT.0 ) THEN
  696. JP2 = -JP2
  697. * (Here, J is a diagonal index)
  698. J = J + 1
  699. JP1 = -IPIV( J )
  700. KSTEP = 2
  701. END IF
  702. * (NOTE: Here, J is used to determine row length. Length N-J+1
  703. * of the rows to swap back doesn't include diagonal element)
  704. J = J + 1
  705. IF( JP2.NE.JJ .AND. J.LE.N )
  706. $ CALL ZSWAP( N-J+1, A( JP2, J ), LDA, A( JJ, J ), LDA )
  707. JJ = JJ + 1
  708. IF( KSTEP.EQ.2 .AND. JP1.NE.JJ .AND. J.LE.N )
  709. $ CALL ZSWAP( N-J+1, A( JP1, J ), LDA, A( JJ, J ), LDA )
  710. IF( J.LT.N )
  711. $ GO TO 60
  712. *
  713. * Set KB to the number of columns factorized
  714. *
  715. KB = N - K
  716. *
  717. ELSE
  718. *
  719. * Factorize the leading columns of A using the lower triangle
  720. * of A and working forwards, and compute the matrix W = L21*D
  721. * for use in updating A22 (note that conjg(W) is actually stored)
  722. *
  723. * K is the main loop index, increasing from 1 in steps of 1 or 2
  724. *
  725. K = 1
  726. 70 CONTINUE
  727. *
  728. * Exit from loop
  729. *
  730. IF( ( K.GE.NB .AND. NB.LT.N ) .OR. K.GT.N )
  731. $ GO TO 90
  732. *
  733. KSTEP = 1
  734. P = K
  735. *
  736. * Copy column K of A to column K of W and update column K of W
  737. *
  738. W( K, K ) = DBLE( A( K, K ) )
  739. IF( K.LT.N )
  740. $ CALL ZCOPY( N-K, A( K+1, K ), 1, W( K+1, K ), 1 )
  741. IF( K.GT.1 ) THEN
  742. CALL ZGEMV( 'No transpose', N-K+1, K-1, -CONE, A( K, 1 ),
  743. $ LDA, W( K, 1 ), LDW, CONE, W( K, K ), 1 )
  744. W( K, K ) = DBLE( W( K, K ) )
  745. END IF
  746. *
  747. * Determine rows and columns to be interchanged and whether
  748. * a 1-by-1 or 2-by-2 pivot block will be used
  749. *
  750. ABSAKK = ABS( DBLE( W( K, K ) ) )
  751. *
  752. * IMAX is the row-index of the largest off-diagonal element in
  753. * column K, and COLMAX is its absolute value.
  754. * Determine both COLMAX and IMAX.
  755. *
  756. IF( K.LT.N ) THEN
  757. IMAX = K + IZAMAX( N-K, W( K+1, K ), 1 )
  758. COLMAX = CABS1( W( IMAX, K ) )
  759. ELSE
  760. COLMAX = ZERO
  761. END IF
  762. *
  763. IF( MAX( ABSAKK, COLMAX ).EQ.ZERO ) THEN
  764. *
  765. * Column K is zero or underflow: set INFO and continue
  766. *
  767. IF( INFO.EQ.0 )
  768. $ INFO = K
  769. KP = K
  770. A( K, K ) = DBLE( W( K, K ) )
  771. IF( K.LT.N )
  772. $ CALL ZCOPY( N-K, W( K+1, K ), 1, A( K+1, K ), 1 )
  773. ELSE
  774. *
  775. * ============================================================
  776. *
  777. * BEGIN pivot search
  778. *
  779. * Case(1)
  780. * Equivalent to testing for ABSAKK.GE.ALPHA*COLMAX
  781. * (used to handle NaN and Inf)
  782. *
  783. IF( .NOT.( ABSAKK.LT.ALPHA*COLMAX ) ) THEN
  784. *
  785. * no interchange, use 1-by-1 pivot block
  786. *
  787. KP = K
  788. *
  789. ELSE
  790. *
  791. DONE = .FALSE.
  792. *
  793. * Loop until pivot found
  794. *
  795. 72 CONTINUE
  796. *
  797. * BEGIN pivot search loop body
  798. *
  799. *
  800. * Copy column IMAX to column k+1 of W and update it
  801. *
  802. CALL ZCOPY( IMAX-K, A( IMAX, K ), LDA, W( K, K+1 ), 1)
  803. CALL ZLACGV( IMAX-K, W( K, K+1 ), 1 )
  804. W( IMAX, K+1 ) = DBLE( A( IMAX, IMAX ) )
  805. *
  806. IF( IMAX.LT.N )
  807. $ CALL ZCOPY( N-IMAX, A( IMAX+1, IMAX ), 1,
  808. $ W( IMAX+1, K+1 ), 1 )
  809. *
  810. IF( K.GT.1 ) THEN
  811. CALL ZGEMV( 'No transpose', N-K+1, K-1, -CONE,
  812. $ A( K, 1 ), LDA, W( IMAX, 1 ), LDW,
  813. $ CONE, W( K, K+1 ), 1 )
  814. W( IMAX, K+1 ) = DBLE( W( IMAX, K+1 ) )
  815. END IF
  816. *
  817. * JMAX is the column-index of the largest off-diagonal
  818. * element in row IMAX, and ROWMAX is its absolute value.
  819. * Determine both ROWMAX and JMAX.
  820. *
  821. IF( IMAX.NE.K ) THEN
  822. JMAX = K - 1 + IZAMAX( IMAX-K, W( K, K+1 ), 1 )
  823. ROWMAX = CABS1( W( JMAX, K+1 ) )
  824. ELSE
  825. ROWMAX = ZERO
  826. END IF
  827. *
  828. IF( IMAX.LT.N ) THEN
  829. ITEMP = IMAX + IZAMAX( N-IMAX, W( IMAX+1, K+1 ), 1)
  830. DTEMP = CABS1( W( ITEMP, K+1 ) )
  831. IF( DTEMP.GT.ROWMAX ) THEN
  832. ROWMAX = DTEMP
  833. JMAX = ITEMP
  834. END IF
  835. END IF
  836. *
  837. * Case(2)
  838. * Equivalent to testing for
  839. * ABS( REAL( W( IMAX,K+1 ) ) ).GE.ALPHA*ROWMAX
  840. * (used to handle NaN and Inf)
  841. *
  842. IF( .NOT.( ABS( DBLE( W( IMAX,K+1 ) ) )
  843. $ .LT.ALPHA*ROWMAX ) ) THEN
  844. *
  845. * interchange rows and columns K and IMAX,
  846. * use 1-by-1 pivot block
  847. *
  848. KP = IMAX
  849. *
  850. * copy column K+1 of W to column K of W
  851. *
  852. CALL ZCOPY( N-K+1, W( K, K+1 ), 1, W( K, K ), 1 )
  853. *
  854. DONE = .TRUE.
  855. *
  856. * Case(3)
  857. * Equivalent to testing for ROWMAX.EQ.COLMAX,
  858. * (used to handle NaN and Inf)
  859. *
  860. ELSE IF( ( P.EQ.JMAX ) .OR. ( ROWMAX.LE.COLMAX ) )
  861. $ THEN
  862. *
  863. * interchange rows and columns K+1 and IMAX,
  864. * use 2-by-2 pivot block
  865. *
  866. KP = IMAX
  867. KSTEP = 2
  868. DONE = .TRUE.
  869. *
  870. * Case(4)
  871. ELSE
  872. *
  873. * Pivot not found: set params and repeat
  874. *
  875. P = IMAX
  876. COLMAX = ROWMAX
  877. IMAX = JMAX
  878. *
  879. * Copy updated JMAXth (next IMAXth) column to Kth of W
  880. *
  881. CALL ZCOPY( N-K+1, W( K, K+1 ), 1, W( K, K ), 1 )
  882. *
  883. END IF
  884. *
  885. *
  886. * End pivot search loop body
  887. *
  888. IF( .NOT.DONE ) GOTO 72
  889. *
  890. END IF
  891. *
  892. * END pivot search
  893. *
  894. * ============================================================
  895. *
  896. * KK is the column of A where pivoting step stopped
  897. *
  898. KK = K + KSTEP - 1
  899. *
  900. * Interchange rows and columns P and K (only for 2-by-2 pivot).
  901. * Updated column P is already stored in column K of W.
  902. *
  903. IF( ( KSTEP.EQ.2 ) .AND. ( P.NE.K ) ) THEN
  904. *
  905. * Copy non-updated column KK-1 to column P of submatrix A
  906. * at step K. No need to copy element into columns
  907. * K and K+1 of A for 2-by-2 pivot, since these columns
  908. * will be later overwritten.
  909. *
  910. A( P, P ) = DBLE( A( K, K ) )
  911. CALL ZCOPY( P-K-1, A( K+1, K ), 1, A( P, K+1 ), LDA )
  912. CALL ZLACGV( P-K-1, A( P, K+1 ), LDA )
  913. IF( P.LT.N )
  914. $ CALL ZCOPY( N-P, A( P+1, K ), 1, A( P+1, P ), 1 )
  915. *
  916. * Interchange rows K and P in first K-1 columns of A
  917. * (columns K and K+1 of A for 2-by-2 pivot will be
  918. * later overwritten). Interchange rows K and P
  919. * in first KK columns of W.
  920. *
  921. IF( K.GT.1 )
  922. $ CALL ZSWAP( K-1, A( K, 1 ), LDA, A( P, 1 ), LDA )
  923. CALL ZSWAP( KK, W( K, 1 ), LDW, W( P, 1 ), LDW )
  924. END IF
  925. *
  926. * Interchange rows and columns KP and KK.
  927. * Updated column KP is already stored in column KK of W.
  928. *
  929. IF( KP.NE.KK ) THEN
  930. *
  931. * Copy non-updated column KK to column KP of submatrix A
  932. * at step K. No need to copy element into column K
  933. * (or K and K+1 for 2-by-2 pivot) of A, since these columns
  934. * will be later overwritten.
  935. *
  936. A( KP, KP ) = DBLE( A( KK, KK ) )
  937. CALL ZCOPY( KP-KK-1, A( KK+1, KK ), 1, A( KP, KK+1 ),
  938. $ LDA )
  939. CALL ZLACGV( KP-KK-1, A( KP, KK+1 ), LDA )
  940. IF( KP.LT.N )
  941. $ CALL ZCOPY( N-KP, A( KP+1, KK ), 1, A( KP+1, KP ), 1 )
  942. *
  943. * Interchange rows KK and KP in first K-1 columns of A
  944. * (column K (or K and K+1 for 2-by-2 pivot) of A will be
  945. * later overwritten). Interchange rows KK and KP
  946. * in first KK columns of W.
  947. *
  948. IF( K.GT.1 )
  949. $ CALL ZSWAP( K-1, A( KK, 1 ), LDA, A( KP, 1 ), LDA )
  950. CALL ZSWAP( KK, W( KK, 1 ), LDW, W( KP, 1 ), LDW )
  951. END IF
  952. *
  953. IF( KSTEP.EQ.1 ) THEN
  954. *
  955. * 1-by-1 pivot block D(k): column k of W now holds
  956. *
  957. * W(k) = L(k)*D(k),
  958. *
  959. * where L(k) is the k-th column of L
  960. *
  961. * (1) Store subdiag. elements of column L(k)
  962. * and 1-by-1 block D(k) in column k of A.
  963. * (NOTE: Diagonal element L(k,k) is a UNIT element
  964. * and not stored)
  965. * A(k,k) := D(k,k) = W(k,k)
  966. * A(k+1:N,k) := L(k+1:N,k) = W(k+1:N,k)/D(k,k)
  967. *
  968. * (NOTE: No need to use for Hermitian matrix
  969. * A( K, K ) = REAL( W( K, K) ) to separately copy diagonal
  970. * element D(k,k) from W (potentially saves only one load))
  971. CALL ZCOPY( N-K+1, W( K, K ), 1, A( K, K ), 1 )
  972. IF( K.LT.N ) THEN
  973. *
  974. * (NOTE: No need to check if A(k,k) is NOT ZERO,
  975. * since that was ensured earlier in pivot search:
  976. * case A(k,k) = 0 falls into 2x2 pivot case(3))
  977. *
  978. * Handle division by a small number
  979. *
  980. T = DBLE( A( K, K ) )
  981. IF( ABS( T ).GE.SFMIN ) THEN
  982. R1 = ONE / T
  983. CALL ZDSCAL( N-K, R1, A( K+1, K ), 1 )
  984. ELSE
  985. DO 74 II = K + 1, N
  986. A( II, K ) = A( II, K ) / T
  987. 74 CONTINUE
  988. END IF
  989. *
  990. * (2) Conjugate column W(k)
  991. *
  992. CALL ZLACGV( N-K, W( K+1, K ), 1 )
  993. END IF
  994. *
  995. ELSE
  996. *
  997. * 2-by-2 pivot block D(k): columns k and k+1 of W now hold
  998. *
  999. * ( W(k) W(k+1) ) = ( L(k) L(k+1) )*D(k)
  1000. *
  1001. * where L(k) and L(k+1) are the k-th and (k+1)-th columns
  1002. * of L
  1003. *
  1004. * (1) Store L(k+2:N,k) and L(k+2:N,k+1) and 2-by-2
  1005. * block D(k:k+1,k:k+1) in columns k and k+1 of A.
  1006. * NOTE: 2-by-2 diagonal block L(k:k+1,k:k+1) is a UNIT
  1007. * block and not stored.
  1008. * A(k:k+1,k:k+1) := D(k:k+1,k:k+1) = W(k:k+1,k:k+1)
  1009. * A(k+2:N,k:k+1) := L(k+2:N,k:k+1) =
  1010. * = W(k+2:N,k:k+1) * ( D(k:k+1,k:k+1)**(-1) )
  1011. *
  1012. IF( K.LT.N-1 ) THEN
  1013. *
  1014. * Factor out the columns of the inverse of 2-by-2 pivot
  1015. * block D, so that each column contains 1, to reduce the
  1016. * number of FLOPS when we multiply panel
  1017. * ( W(kw-1) W(kw) ) by this inverse, i.e. by D**(-1).
  1018. *
  1019. * D**(-1) = ( d11 cj(d21) )**(-1) =
  1020. * ( d21 d22 )
  1021. *
  1022. * = 1/(d11*d22-|d21|**2) * ( ( d22) (-cj(d21) ) ) =
  1023. * ( (-d21) ( d11 ) )
  1024. *
  1025. * = 1/(|d21|**2) * 1/((d11/cj(d21))*(d22/d21)-1) *
  1026. *
  1027. * * ( d21*( d22/d21 ) conj(d21)*( - 1 ) ) =
  1028. * ( ( -1 ) ( d11/conj(d21) ) )
  1029. *
  1030. * = 1/(|d21|**2) * 1/(D22*D11-1) *
  1031. *
  1032. * * ( d21*( D11 ) conj(d21)*( -1 ) ) =
  1033. * ( ( -1 ) ( D22 ) )
  1034. *
  1035. * = (1/|d21|**2) * T * ( d21*( D11 ) conj(d21)*( -1 ) ) =
  1036. * ( ( -1 ) ( D22 ) )
  1037. *
  1038. * = ( (T/conj(d21))*( D11 ) (T/d21)*( -1 ) ) =
  1039. * ( ( -1 ) ( D22 ) )
  1040. *
  1041. * Handle division by a small number. (NOTE: order of
  1042. * operations is important)
  1043. *
  1044. * = ( T*(( D11 )/conj(D21)) T*(( -1 )/D21 ) )
  1045. * ( (( -1 ) ) (( D22 ) ) ),
  1046. *
  1047. * where D11 = d22/d21,
  1048. * D22 = d11/conj(d21),
  1049. * D21 = d21,
  1050. * T = 1/(D22*D11-1).
  1051. *
  1052. * (NOTE: No need to check for division by ZERO,
  1053. * since that was ensured earlier in pivot search:
  1054. * (a) d21 != 0 in 2x2 pivot case(4),
  1055. * since |d21| should be larger than |d11| and |d22|;
  1056. * (b) (D22*D11 - 1) != 0, since from (a),
  1057. * both |D11| < 1, |D22| < 1, hence |D22*D11| << 1.)
  1058. *
  1059. D21 = W( K+1, K )
  1060. D11 = W( K+1, K+1 ) / D21
  1061. D22 = W( K, K ) / DCONJG( D21 )
  1062. T = ONE / ( DBLE( D11*D22 )-ONE )
  1063. *
  1064. * Update elements in columns A(k) and A(k+1) as
  1065. * dot products of rows of ( W(k) W(k+1) ) and columns
  1066. * of D**(-1)
  1067. *
  1068. DO 80 J = K + 2, N
  1069. A( J, K ) = T*( ( D11*W( J, K )-W( J, K+1 ) ) /
  1070. $ DCONJG( D21 ) )
  1071. A( J, K+1 ) = T*( ( D22*W( J, K+1 )-W( J, K ) ) /
  1072. $ D21 )
  1073. 80 CONTINUE
  1074. END IF
  1075. *
  1076. * Copy D(k) to A
  1077. *
  1078. A( K, K ) = W( K, K )
  1079. A( K+1, K ) = W( K+1, K )
  1080. A( K+1, K+1 ) = W( K+1, K+1 )
  1081. *
  1082. * (2) Conjugate columns W(k) and W(k+1)
  1083. *
  1084. CALL ZLACGV( N-K, W( K+1, K ), 1 )
  1085. CALL ZLACGV( N-K-1, W( K+2, K+1 ), 1 )
  1086. *
  1087. END IF
  1088. *
  1089. END IF
  1090. *
  1091. * Store details of the interchanges in IPIV
  1092. *
  1093. IF( KSTEP.EQ.1 ) THEN
  1094. IPIV( K ) = KP
  1095. ELSE
  1096. IPIV( K ) = -P
  1097. IPIV( K+1 ) = -KP
  1098. END IF
  1099. *
  1100. * Increase K and return to the start of the main loop
  1101. *
  1102. K = K + KSTEP
  1103. GO TO 70
  1104. *
  1105. 90 CONTINUE
  1106. *
  1107. * Update the lower triangle of A22 (= A(k:n,k:n)) as
  1108. *
  1109. * A22 := A22 - L21*D*L21**H = A22 - L21*W**H
  1110. *
  1111. * computing blocks of NB columns at a time (note that conjg(W) is
  1112. * actually stored)
  1113. *
  1114. DO 110 J = K, N, NB
  1115. JB = MIN( NB, N-J+1 )
  1116. *
  1117. * Update the lower triangle of the diagonal block
  1118. *
  1119. DO 100 JJ = J, J + JB - 1
  1120. A( JJ, JJ ) = DBLE( A( JJ, JJ ) )
  1121. CALL ZGEMV( 'No transpose', J+JB-JJ, K-1, -CONE,
  1122. $ A( JJ, 1 ), LDA, W( JJ, 1 ), LDW, CONE,
  1123. $ A( JJ, JJ ), 1 )
  1124. A( JJ, JJ ) = DBLE( A( JJ, JJ ) )
  1125. 100 CONTINUE
  1126. *
  1127. * Update the rectangular subdiagonal block
  1128. *
  1129. IF( J+JB.LE.N )
  1130. $ CALL ZGEMM( 'No transpose', 'Transpose', N-J-JB+1, JB,
  1131. $ K-1, -CONE, A( J+JB, 1 ), LDA, W( J, 1 ),
  1132. $ LDW, CONE, A( J+JB, J ), LDA )
  1133. 110 CONTINUE
  1134. *
  1135. * Put L21 in standard form by partially undoing the interchanges
  1136. * of rows in columns 1:k-1 looping backwards from k-1 to 1
  1137. *
  1138. J = K - 1
  1139. 120 CONTINUE
  1140. *
  1141. * Undo the interchanges (if any) of rows J and JP2
  1142. * (or J and JP2, and J-1 and JP1) at each step J
  1143. *
  1144. KSTEP = 1
  1145. JP1 = 1
  1146. * (Here, J is a diagonal index)
  1147. JJ = J
  1148. JP2 = IPIV( J )
  1149. IF( JP2.LT.0 ) THEN
  1150. JP2 = -JP2
  1151. * (Here, J is a diagonal index)
  1152. J = J - 1
  1153. JP1 = -IPIV( J )
  1154. KSTEP = 2
  1155. END IF
  1156. * (NOTE: Here, J is used to determine row length. Length J
  1157. * of the rows to swap back doesn't include diagonal element)
  1158. J = J - 1
  1159. IF( JP2.NE.JJ .AND. J.GE.1 )
  1160. $ CALL ZSWAP( J, A( JP2, 1 ), LDA, A( JJ, 1 ), LDA )
  1161. JJ = JJ -1
  1162. IF( KSTEP.EQ.2 .AND. JP1.NE.JJ .AND. J.GE.1 )
  1163. $ CALL ZSWAP( J, A( JP1, 1 ), LDA, A( JJ, 1 ), LDA )
  1164. IF( J.GT.1 )
  1165. $ GO TO 120
  1166. *
  1167. * Set KB to the number of columns factorized
  1168. *
  1169. KB = K - 1
  1170. *
  1171. END IF
  1172. RETURN
  1173. *
  1174. * End of ZLAHEF_ROOK
  1175. *
  1176. END