1*> \brief \b CSYTRS_ROOK 2* 3* =========== DOCUMENTATION =========== 4* 5* Online html documentation available at 6* http://www.netlib.org/lapack/explore-html/ 7* 8*> \htmlonly 9*> Download CSYTRS_ROOK + dependencies 10*> <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/csytrs_rook.f"> 11*> [TGZ]</a> 12*> <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/csytrs_rook.f"> 13*> [ZIP]</a> 14*> <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/csytrs_rook.f"> 15*> [TXT]</a> 16*> \endhtmlonly 17* 18* Definition: 19* =========== 20* 21* SUBROUTINE CSYTRS_ROOK( UPLO, N, NRHS, A, LDA, IPIV, B, LDB, INFO ) 22* 23* .. Scalar Arguments .. 24* CHARACTER UPLO 25* INTEGER INFO, LDA, LDB, N, NRHS 26* .. 27* .. Array Arguments .. 28* INTEGER IPIV( * ) 29* COMPLEX A( LDA, * ), B( LDB, * ) 30* .. 31* 32* 33*> \par Purpose: 34* ============= 35*> 36*> \verbatim 37*> 38*> CSYTRS_ROOK solves a system of linear equations A*X = B with 39*> a complex symmetric matrix A using the factorization A = U*D*U**T or 40*> A = L*D*L**T computed by CSYTRF_ROOK. 41*> \endverbatim 42* 43* Arguments: 44* ========== 45* 46*> \param[in] UPLO 47*> \verbatim 48*> UPLO is CHARACTER*1 49*> Specifies whether the details of the factorization are stored 50*> as an upper or lower triangular matrix. 51*> = 'U': Upper triangular, form is A = U*D*U**T; 52*> = 'L': Lower triangular, form is A = L*D*L**T. 53*> \endverbatim 54*> 55*> \param[in] N 56*> \verbatim 57*> N is INTEGER 58*> The order of the matrix A. N >= 0. 59*> \endverbatim 60*> 61*> \param[in] NRHS 62*> \verbatim 63*> NRHS is INTEGER 64*> The number of right hand sides, i.e., the number of columns 65*> of the matrix B. NRHS >= 0. 66*> \endverbatim 67*> 68*> \param[in] A 69*> \verbatim 70*> A is COMPLEX array, dimension (LDA,N) 71*> The block diagonal matrix D and the multipliers used to 72*> obtain the factor U or L as computed by CSYTRF_ROOK. 73*> \endverbatim 74*> 75*> \param[in] LDA 76*> \verbatim 77*> LDA is INTEGER 78*> The leading dimension of the array A. LDA >= max(1,N). 79*> \endverbatim 80*> 81*> \param[in] IPIV 82*> \verbatim 83*> IPIV is INTEGER array, dimension (N) 84*> Details of the interchanges and the block structure of D 85*> as determined by CSYTRF_ROOK. 86*> \endverbatim 87*> 88*> \param[in,out] B 89*> \verbatim 90*> B is COMPLEX array, dimension (LDB,NRHS) 91*> On entry, the right hand side matrix B. 92*> On exit, the solution matrix X. 93*> \endverbatim 94*> 95*> \param[in] LDB 96*> \verbatim 97*> LDB is INTEGER 98*> The leading dimension of the array B. LDB >= max(1,N). 99*> \endverbatim 100*> 101*> \param[out] INFO 102*> \verbatim 103*> INFO is INTEGER 104*> = 0: successful exit 105*> < 0: if INFO = -i, the i-th argument had an illegal value 106*> \endverbatim 107* 108* Authors: 109* ======== 110* 111*> \author Univ. of Tennessee 112*> \author Univ. of California Berkeley 113*> \author Univ. of Colorado Denver 114*> \author NAG Ltd. 115* 116*> \ingroup complexSYcomputational 117* 118*> \par Contributors: 119* ================== 120*> 121*> \verbatim 122*> 123*> December 2016, Igor Kozachenko, 124*> Computer Science Division, 125*> University of California, Berkeley 126*> 127*> September 2007, Sven Hammarling, Nicholas J. Higham, Craig Lucas, 128*> School of Mathematics, 129*> University of Manchester 130*> 131*> \endverbatim 132* 133* ===================================================================== 134 SUBROUTINE CSYTRS_ROOK( UPLO, N, NRHS, A, LDA, IPIV, B, LDB, 135 $ INFO ) 136* 137* -- LAPACK computational routine -- 138* -- LAPACK is a software package provided by Univ. of Tennessee, -- 139* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- 140* 141* .. Scalar Arguments .. 142 CHARACTER UPLO 143 INTEGER INFO, LDA, LDB, N, NRHS 144* .. 145* .. Array Arguments .. 146 INTEGER IPIV( * ) 147 COMPLEX A( LDA, * ), B( LDB, * ) 148* .. 149* 150* ===================================================================== 151* 152* .. Parameters .. 153 COMPLEX CONE 154 PARAMETER ( CONE = ( 1.0E+0, 0.0E+0 ) ) 155* .. 156* .. Local Scalars .. 157 LOGICAL UPPER 158 INTEGER J, K, KP 159 COMPLEX AK, AKM1, AKM1K, BK, BKM1, DENOM 160* .. 161* .. External Functions .. 162 LOGICAL LSAME 163 EXTERNAL LSAME 164* .. 165* .. External Subroutines .. 166 EXTERNAL CGEMV, CGERU, CSCAL, CSWAP, XERBLA 167* .. 168* .. Intrinsic Functions .. 169 INTRINSIC MAX 170* .. 171* .. Executable Statements .. 172* 173 INFO = 0 174 UPPER = LSAME( UPLO, 'U' ) 175 IF( .NOT.UPPER .AND. .NOT.LSAME( UPLO, 'L' ) ) THEN 176 INFO = -1 177 ELSE IF( N.LT.0 ) THEN 178 INFO = -2 179 ELSE IF( NRHS.LT.0 ) THEN 180 INFO = -3 181 ELSE IF( LDA.LT.MAX( 1, N ) ) THEN 182 INFO = -5 183 ELSE IF( LDB.LT.MAX( 1, N ) ) THEN 184 INFO = -8 185 END IF 186 IF( INFO.NE.0 ) THEN 187 CALL XERBLA( 'CSYTRS_ROOK', -INFO ) 188 RETURN 189 END IF 190* 191* Quick return if possible 192* 193 IF( N.EQ.0 .OR. NRHS.EQ.0 ) 194 $ RETURN 195* 196 IF( UPPER ) THEN 197* 198* Solve A*X = B, where A = U*D*U**T. 199* 200* First solve U*D*X = B, overwriting B with X. 201* 202* K is the main loop index, decreasing from N to 1 in steps of 203* 1 or 2, depending on the size of the diagonal blocks. 204* 205 K = N 206 10 CONTINUE 207* 208* If K < 1, exit from loop. 209* 210 IF( K.LT.1 ) 211 $ GO TO 30 212* 213 IF( IPIV( K ).GT.0 ) THEN 214* 215* 1 x 1 diagonal block 216* 217* Interchange rows K and IPIV(K). 218* 219 KP = IPIV( K ) 220 IF( KP.NE.K ) 221 $ CALL CSWAP( NRHS, B( K, 1 ), LDB, B( KP, 1 ), LDB ) 222* 223* Multiply by inv(U(K)), where U(K) is the transformation 224* stored in column K of A. 225* 226 CALL CGERU( K-1, NRHS, -CONE, A( 1, K ), 1, B( K, 1 ), LDB, 227 $ B( 1, 1 ), LDB ) 228* 229* Multiply by the inverse of the diagonal block. 230* 231 CALL CSCAL( NRHS, CONE / A( K, K ), B( K, 1 ), LDB ) 232 K = K - 1 233 ELSE 234* 235* 2 x 2 diagonal block 236* 237* Interchange rows K and -IPIV(K) THEN K-1 and -IPIV(K-1) 238* 239 KP = -IPIV( K ) 240 IF( KP.NE.K ) 241 $ CALL CSWAP( NRHS, B( K, 1 ), LDB, B( KP, 1 ), LDB ) 242* 243 KP = -IPIV( K-1 ) 244 IF( KP.NE.K-1 ) 245 $ CALL CSWAP( NRHS, B( K-1, 1 ), LDB, B( KP, 1 ), LDB ) 246* 247* Multiply by inv(U(K)), where U(K) is the transformation 248* stored in columns K-1 and K of A. 249* 250 IF( K.GT.2 ) THEN 251 CALL CGERU( K-2, NRHS,-CONE, A( 1, K ), 1, B( K, 1 ), 252 $ LDB, B( 1, 1 ), LDB ) 253 CALL CGERU( K-2, NRHS,-CONE, A( 1, K-1 ), 1, B( K-1, 1 ), 254 $ LDB, B( 1, 1 ), LDB ) 255 END IF 256* 257* Multiply by the inverse of the diagonal block. 258* 259 AKM1K = A( K-1, K ) 260 AKM1 = A( K-1, K-1 ) / AKM1K 261 AK = A( K, K ) / AKM1K 262 DENOM = AKM1*AK - CONE 263 DO 20 J = 1, NRHS 264 BKM1 = B( K-1, J ) / AKM1K 265 BK = B( K, J ) / AKM1K 266 B( K-1, J ) = ( AK*BKM1-BK ) / DENOM 267 B( K, J ) = ( AKM1*BK-BKM1 ) / DENOM 268 20 CONTINUE 269 K = K - 2 270 END IF 271* 272 GO TO 10 273 30 CONTINUE 274* 275* Next solve U**T *X = B, overwriting B with X. 276* 277* K is the main loop index, increasing from 1 to N in steps of 278* 1 or 2, depending on the size of the diagonal blocks. 279* 280 K = 1 281 40 CONTINUE 282* 283* If K > N, exit from loop. 284* 285 IF( K.GT.N ) 286 $ GO TO 50 287* 288 IF( IPIV( K ).GT.0 ) THEN 289* 290* 1 x 1 diagonal block 291* 292* Multiply by inv(U**T(K)), where U(K) is the transformation 293* stored in column K of A. 294* 295 IF( K.GT.1 ) 296 $ CALL CGEMV( 'Transpose', K-1, NRHS, -CONE, B, 297 $ LDB, A( 1, K ), 1, CONE, B( K, 1 ), LDB ) 298* 299* Interchange rows K and IPIV(K). 300* 301 KP = IPIV( K ) 302 IF( KP.NE.K ) 303 $ CALL CSWAP( NRHS, B( K, 1 ), LDB, B( KP, 1 ), LDB ) 304 K = K + 1 305 ELSE 306* 307* 2 x 2 diagonal block 308* 309* Multiply by inv(U**T(K+1)), where U(K+1) is the transformation 310* stored in columns K and K+1 of A. 311* 312 IF( K.GT.1 ) THEN 313 CALL CGEMV( 'Transpose', K-1, NRHS, -CONE, B, 314 $ LDB, A( 1, K ), 1, CONE, B( K, 1 ), LDB ) 315 CALL CGEMV( 'Transpose', K-1, NRHS, -CONE, B, 316 $ LDB, A( 1, K+1 ), 1, CONE, B( K+1, 1 ), LDB ) 317 END IF 318* 319* Interchange rows K and -IPIV(K) THEN K+1 and -IPIV(K+1). 320* 321 KP = -IPIV( K ) 322 IF( KP.NE.K ) 323 $ CALL CSWAP( NRHS, B( K, 1 ), LDB, B( KP, 1 ), LDB ) 324* 325 KP = -IPIV( K+1 ) 326 IF( KP.NE.K+1 ) 327 $ CALL CSWAP( NRHS, B( K+1, 1 ), LDB, B( KP, 1 ), LDB ) 328* 329 K = K + 2 330 END IF 331* 332 GO TO 40 333 50 CONTINUE 334* 335 ELSE 336* 337* Solve A*X = B, where A = L*D*L**T. 338* 339* First solve L*D*X = B, overwriting B with X. 340* 341* K is the main loop index, increasing from 1 to N in steps of 342* 1 or 2, depending on the size of the diagonal blocks. 343* 344 K = 1 345 60 CONTINUE 346* 347* If K > N, exit from loop. 348* 349 IF( K.GT.N ) 350 $ GO TO 80 351* 352 IF( IPIV( K ).GT.0 ) THEN 353* 354* 1 x 1 diagonal block 355* 356* Interchange rows K and IPIV(K). 357* 358 KP = IPIV( K ) 359 IF( KP.NE.K ) 360 $ CALL CSWAP( NRHS, B( K, 1 ), LDB, B( KP, 1 ), LDB ) 361* 362* Multiply by inv(L(K)), where L(K) is the transformation 363* stored in column K of A. 364* 365 IF( K.LT.N ) 366 $ CALL CGERU( N-K, NRHS, -CONE, A( K+1, K ), 1, B( K, 1 ), 367 $ LDB, B( K+1, 1 ), LDB ) 368* 369* Multiply by the inverse of the diagonal block. 370* 371 CALL CSCAL( NRHS, CONE / A( K, K ), B( K, 1 ), LDB ) 372 K = K + 1 373 ELSE 374* 375* 2 x 2 diagonal block 376* 377* Interchange rows K and -IPIV(K) THEN K+1 and -IPIV(K+1) 378* 379 KP = -IPIV( K ) 380 IF( KP.NE.K ) 381 $ CALL CSWAP( NRHS, B( K, 1 ), LDB, B( KP, 1 ), LDB ) 382* 383 KP = -IPIV( K+1 ) 384 IF( KP.NE.K+1 ) 385 $ CALL CSWAP( NRHS, B( K+1, 1 ), LDB, B( KP, 1 ), LDB ) 386* 387* Multiply by inv(L(K)), where L(K) is the transformation 388* stored in columns K and K+1 of A. 389* 390 IF( K.LT.N-1 ) THEN 391 CALL CGERU( N-K-1, NRHS,-CONE, A( K+2, K ), 1, B( K, 1 ), 392 $ LDB, B( K+2, 1 ), LDB ) 393 CALL CGERU( N-K-1, NRHS,-CONE, A( K+2, K+1 ), 1, 394 $ B( K+1, 1 ), LDB, B( K+2, 1 ), LDB ) 395 END IF 396* 397* Multiply by the inverse of the diagonal block. 398* 399 AKM1K = A( K+1, K ) 400 AKM1 = A( K, K ) / AKM1K 401 AK = A( K+1, K+1 ) / AKM1K 402 DENOM = AKM1*AK - CONE 403 DO 70 J = 1, NRHS 404 BKM1 = B( K, J ) / AKM1K 405 BK = B( K+1, J ) / AKM1K 406 B( K, J ) = ( AK*BKM1-BK ) / DENOM 407 B( K+1, J ) = ( AKM1*BK-BKM1 ) / DENOM 408 70 CONTINUE 409 K = K + 2 410 END IF 411* 412 GO TO 60 413 80 CONTINUE 414* 415* Next solve L**T *X = B, overwriting B with X. 416* 417* K is the main loop index, decreasing from N to 1 in steps of 418* 1 or 2, depending on the size of the diagonal blocks. 419* 420 K = N 421 90 CONTINUE 422* 423* If K < 1, exit from loop. 424* 425 IF( K.LT.1 ) 426 $ GO TO 100 427* 428 IF( IPIV( K ).GT.0 ) THEN 429* 430* 1 x 1 diagonal block 431* 432* Multiply by inv(L**T(K)), where L(K) is the transformation 433* stored in column K of A. 434* 435 IF( K.LT.N ) 436 $ CALL CGEMV( 'Transpose', N-K, NRHS, -CONE, B( K+1, 1 ), 437 $ LDB, A( K+1, K ), 1, CONE, B( K, 1 ), LDB ) 438* 439* Interchange rows K and IPIV(K). 440* 441 KP = IPIV( K ) 442 IF( KP.NE.K ) 443 $ CALL CSWAP( NRHS, B( K, 1 ), LDB, B( KP, 1 ), LDB ) 444 K = K - 1 445 ELSE 446* 447* 2 x 2 diagonal block 448* 449* Multiply by inv(L**T(K-1)), where L(K-1) is the transformation 450* stored in columns K-1 and K of A. 451* 452 IF( K.LT.N ) THEN 453 CALL CGEMV( 'Transpose', N-K, NRHS, -CONE, B( K+1, 1 ), 454 $ LDB, A( K+1, K ), 1, CONE, B( K, 1 ), LDB ) 455 CALL CGEMV( 'Transpose', N-K, NRHS, -CONE, B( K+1, 1 ), 456 $ LDB, A( K+1, K-1 ), 1, CONE, B( K-1, 1 ), 457 $ LDB ) 458 END IF 459* 460* Interchange rows K and -IPIV(K) THEN K-1 and -IPIV(K-1) 461* 462 KP = -IPIV( K ) 463 IF( KP.NE.K ) 464 $ CALL CSWAP( NRHS, B( K, 1 ), LDB, B( KP, 1 ), LDB ) 465* 466 KP = -IPIV( K-1 ) 467 IF( KP.NE.K-1 ) 468 $ CALL CSWAP( NRHS, B( K-1, 1 ), LDB, B( KP, 1 ), LDB ) 469* 470 K = K - 2 471 END IF 472* 473 GO TO 90 474 100 CONTINUE 475 END IF 476* 477 RETURN 478* 479* End of CSYTRS_ROOK 480* 481 END 482