gonum.org/v1/gonum@v0.14.0/lapack/gonum/dtrevc3.go (about) 1 // Copyright ©2016 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package gonum 6 7 import ( 8 "math" 9 10 "gonum.org/v1/gonum/blas" 11 "gonum.org/v1/gonum/blas/blas64" 12 "gonum.org/v1/gonum/lapack" 13 ) 14 15 // Dtrevc3 computes some or all of the right and/or left eigenvectors of an n×n 16 // upper quasi-triangular matrix T in Schur canonical form. Matrices of this 17 // type are produced by the Schur factorization of a real general matrix A 18 // 19 // A = Q T Qᵀ, 20 // 21 // as computed by Dhseqr. 22 // 23 // The right eigenvector x of T corresponding to an 24 // eigenvalue λ is defined by 25 // 26 // T x = λ x, 27 // 28 // and the left eigenvector y is defined by 29 // 30 // yᵀ T = λ yᵀ. 31 // 32 // The eigenvalues are read directly from the diagonal blocks of T. 33 // 34 // This routine returns the matrices X and/or Y of right and left eigenvectors 35 // of T, or the products Q*X and/or Q*Y, where Q is an input matrix. If Q is the 36 // orthogonal factor that reduces a matrix A to Schur form T, then Q*X and Q*Y 37 // are the matrices of right and left eigenvectors of A. 38 // 39 // If side == lapack.EVRight, only right eigenvectors will be computed. 40 // If side == lapack.EVLeft, only left eigenvectors will be computed. 41 // If side == lapack.EVBoth, both right and left eigenvectors will be computed. 42 // For other values of side, Dtrevc3 will panic. 43 // 44 // If howmny == lapack.EVAll, all right and/or left eigenvectors will be 45 // computed. 46 // If howmny == lapack.EVAllMulQ, all right and/or left eigenvectors will be 47 // computed and multiplied from left by the matrices in VR and/or VL. 48 // If howmny == lapack.EVSelected, right and/or left eigenvectors will be 49 // computed as indicated by selected. 50 // For other values of howmny, Dtrevc3 will panic. 51 // 52 // selected specifies which eigenvectors will be computed. It must have length n 53 // if howmny == lapack.EVSelected, and it is not referenced otherwise. 54 // If w_j is a real eigenvalue, the corresponding real eigenvector will be 55 // computed if selected[j] is true. 56 // If w_j and w_{j+1} are the real and imaginary parts of a complex eigenvalue, 57 // the corresponding complex eigenvector is computed if either selected[j] or 58 // selected[j+1] is true, and on return selected[j] will be set to true and 59 // selected[j+1] will be set to false. 60 // 61 // VL and VR are n×mm matrices. If howmny is lapack.EVAll or 62 // lapack.AllEVMulQ, mm must be at least n. If howmny is 63 // lapack.EVSelected, mm must be large enough to store the selected 64 // eigenvectors. Each selected real eigenvector occupies one column and each 65 // selected complex eigenvector occupies two columns. If mm is not sufficiently 66 // large, Dtrevc3 will panic. 67 // 68 // On entry, if howmny is lapack.EVAllMulQ, it is assumed that VL (if side 69 // is lapack.EVLeft or lapack.EVBoth) contains an n×n matrix QL, 70 // and that VR (if side is lapack.EVRight or lapack.EVBoth) contains 71 // an n×n matrix QR. QL and QR are typically the orthogonal matrix Q of Schur 72 // vectors returned by Dhseqr. 73 // 74 // On return, if side is lapack.EVLeft or lapack.EVBoth, 75 // VL will contain: 76 // 77 // if howmny == lapack.EVAll, the matrix Y of left eigenvectors of T, 78 // if howmny == lapack.EVAllMulQ, the matrix Q*Y, 79 // if howmny == lapack.EVSelected, the left eigenvectors of T specified by 80 // selected, stored consecutively in the 81 // columns of VL, in the same order as their 82 // eigenvalues. 83 // 84 // VL is not referenced if side == lapack.EVRight. 85 // 86 // On return, if side is lapack.EVRight or lapack.EVBoth, 87 // VR will contain: 88 // 89 // if howmny == lapack.EVAll, the matrix X of right eigenvectors of T, 90 // if howmny == lapack.EVAllMulQ, the matrix Q*X, 91 // if howmny == lapack.EVSelected, the left eigenvectors of T specified by 92 // selected, stored consecutively in the 93 // columns of VR, in the same order as their 94 // eigenvalues. 95 // 96 // VR is not referenced if side == lapack.EVLeft. 97 // 98 // Complex eigenvectors corresponding to a complex eigenvalue are stored in VL 99 // and VR in two consecutive columns, the first holding the real part, and the 100 // second the imaginary part. 101 // 102 // Each eigenvector will be normalized so that the element of largest magnitude 103 // has magnitude 1. Here the magnitude of a complex number (x,y) is taken to be 104 // |x| + |y|. 105 // 106 // work must have length at least lwork and lwork must be at least max(1,3*n), 107 // otherwise Dtrevc3 will panic. For optimum performance, lwork should be at 108 // least n+2*n*nb, where nb is the optimal blocksize. 109 // 110 // If lwork == -1, instead of performing Dtrevc3, the function only estimates 111 // the optimal workspace size based on n and stores it into work[0]. 112 // 113 // Dtrevc3 returns the number of columns in VL and/or VR actually used to store 114 // the eigenvectors. 115 // 116 // Dtrevc3 is an internal routine. It is exported for testing purposes. 117 func (impl Implementation) Dtrevc3(side lapack.EVSide, howmny lapack.EVHowMany, selected []bool, n int, t []float64, ldt int, vl []float64, ldvl int, vr []float64, ldvr int, mm int, work []float64, lwork int) (m int) { 118 bothv := side == lapack.EVBoth 119 rightv := side == lapack.EVRight || bothv 120 leftv := side == lapack.EVLeft || bothv 121 switch { 122 case !rightv && !leftv: 123 panic(badEVSide) 124 case howmny != lapack.EVAll && howmny != lapack.EVAllMulQ && howmny != lapack.EVSelected: 125 panic(badEVHowMany) 126 case n < 0: 127 panic(nLT0) 128 case ldt < max(1, n): 129 panic(badLdT) 130 case mm < 0: 131 panic(mmLT0) 132 case ldvl < 1: 133 // ldvl and ldvr are also checked below after the computation of 134 // m (number of columns of VL and VR) in case of howmny == EVSelected. 135 panic(badLdVL) 136 case ldvr < 1: 137 panic(badLdVR) 138 case lwork < max(1, 3*n) && lwork != -1: 139 panic(badLWork) 140 case len(work) < max(1, lwork): 141 panic(shortWork) 142 } 143 144 // Quick return if possible. 145 if n == 0 { 146 work[0] = 1 147 return 0 148 } 149 150 // Normally we don't check slice lengths until after the workspace 151 // query. However, even in case of the workspace query we need to 152 // compute and return the value of m, and since the computation accesses t, 153 // we put the length check of t here. 154 if len(t) < (n-1)*ldt+n { 155 panic(shortT) 156 } 157 158 if howmny == lapack.EVSelected { 159 if len(selected) != n { 160 panic(badLenSelected) 161 } 162 // Set m to the number of columns required to store the selected 163 // eigenvectors, and standardize the slice selected. 164 // Each selected real eigenvector occupies one column and each 165 // selected complex eigenvector occupies two columns. 166 for j := 0; j < n; { 167 if j == n-1 || t[(j+1)*ldt+j] == 0 { 168 // Diagonal 1×1 block corresponding to a 169 // real eigenvalue. 170 if selected[j] { 171 m++ 172 } 173 j++ 174 } else { 175 // Diagonal 2×2 block corresponding to a 176 // complex eigenvalue. 177 if selected[j] || selected[j+1] { 178 selected[j] = true 179 selected[j+1] = false 180 m += 2 181 } 182 j += 2 183 } 184 } 185 } else { 186 m = n 187 } 188 if mm < m { 189 panic(badMm) 190 } 191 192 // Quick return in case of a workspace query. 193 nb := impl.Ilaenv(1, "DTREVC", string(side)+string(howmny), n, -1, -1, -1) 194 if lwork == -1 { 195 work[0] = float64(n + 2*n*nb) 196 return m 197 } 198 199 // Quick return if no eigenvectors were selected. 200 if m == 0 { 201 return 0 202 } 203 204 switch { 205 case leftv && ldvl < mm: 206 panic(badLdVL) 207 case leftv && len(vl) < (n-1)*ldvl+mm: 208 panic(shortVL) 209 210 case rightv && ldvr < mm: 211 panic(badLdVR) 212 case rightv && len(vr) < (n-1)*ldvr+mm: 213 panic(shortVR) 214 } 215 216 // Use blocked version of back-transformation if sufficient workspace. 217 // Zero-out the workspace to avoid potential NaN propagation. 218 const ( 219 nbmin = 8 220 nbmax = 128 221 ) 222 if howmny == lapack.EVAllMulQ && lwork >= n+2*n*nbmin { 223 nb = min((lwork-n)/(2*n), nbmax) 224 impl.Dlaset(blas.All, n, 1+2*nb, 0, 0, work[:n+2*nb*n], 1+2*nb) 225 } else { 226 nb = 1 227 } 228 229 // Set the constants to control overflow. 230 ulp := dlamchP 231 smlnum := float64(n) / ulp * dlamchS 232 bignum := (1 - ulp) / smlnum 233 234 // Split work into a vector of column norms and an n×2*nb matrix b. 235 norms := work[:n] 236 ldb := 2 * nb 237 b := work[n : n+n*ldb] 238 239 // Compute 1-norm of each column of strictly upper triangular part of T 240 // to control overflow in triangular solver. 241 norms[0] = 0 242 for j := 1; j < n; j++ { 243 var cn float64 244 for i := 0; i < j; i++ { 245 cn += math.Abs(t[i*ldt+j]) 246 } 247 norms[j] = cn 248 } 249 250 bi := blas64.Implementation() 251 252 var ( 253 x [4]float64 254 255 iv int // Index of column in current block. 256 is int 257 258 // ip is used below to specify the real or complex eigenvalue: 259 // ip == 0, real eigenvalue, 260 // 1, first of conjugate complex pair (wr,wi), 261 // -1, second of conjugate complex pair (wr,wi). 262 ip int 263 iscomplex [nbmax]int // Stores ip for each column in current block. 264 ) 265 266 if side == lapack.EVLeft { 267 goto leftev 268 } 269 270 // Compute right eigenvectors. 271 272 // For complex right vector, iv-1 is for real part and iv for complex 273 // part. Non-blocked version always uses iv=1, blocked version starts 274 // with iv=nb-1 and goes down to 0 or 1. 275 iv = max(2, nb) - 1 276 ip = 0 277 is = m - 1 278 for ki := n - 1; ki >= 0; ki-- { 279 if ip == -1 { 280 // Previous iteration (ki+1) was second of 281 // conjugate pair, so this ki is first of 282 // conjugate pair. 283 ip = 1 284 continue 285 } 286 287 if ki == 0 || t[ki*ldt+ki-1] == 0 { 288 // Last column or zero on sub-diagonal, so this 289 // ki must be real eigenvalue. 290 ip = 0 291 } else { 292 // Non-zero on sub-diagonal, so this ki is 293 // second of conjugate pair. 294 ip = -1 295 } 296 297 if howmny == lapack.EVSelected { 298 if ip == 0 { 299 if !selected[ki] { 300 continue 301 } 302 } else if !selected[ki-1] { 303 continue 304 } 305 } 306 307 // Compute the ki-th eigenvalue (wr,wi). 308 wr := t[ki*ldt+ki] 309 var wi float64 310 if ip != 0 { 311 wi = math.Sqrt(math.Abs(t[ki*ldt+ki-1])) * math.Sqrt(math.Abs(t[(ki-1)*ldt+ki])) 312 } 313 smin := math.Max(ulp*(math.Abs(wr)+math.Abs(wi)), smlnum) 314 315 if ip == 0 { 316 // Real right eigenvector. 317 318 b[ki*ldb+iv] = 1 319 // Form right-hand side. 320 for k := 0; k < ki; k++ { 321 b[k*ldb+iv] = -t[k*ldt+ki] 322 } 323 // Solve upper quasi-triangular system: 324 // [ T[0:ki,0:ki] - wr ]*X = scale*b. 325 for j := ki - 1; j >= 0; { 326 if j == 0 || t[j*ldt+j-1] == 0 { 327 // 1×1 diagonal block. 328 scale, xnorm, _ := impl.Dlaln2(false, 1, 1, smin, 1, t[j*ldt+j:], ldt, 329 1, 1, b[j*ldb+iv:], ldb, wr, 0, x[:1], 2) 330 // Scale X[0,0] to avoid overflow when updating the 331 // right-hand side. 332 if xnorm > 1 && norms[j] > bignum/xnorm { 333 x[0] /= xnorm 334 scale /= xnorm 335 } 336 // Scale if necessary. 337 if scale != 1 { 338 bi.Dscal(ki+1, scale, b[iv:], ldb) 339 } 340 b[j*ldb+iv] = x[0] 341 // Update right-hand side. 342 bi.Daxpy(j, -x[0], t[j:], ldt, b[iv:], ldb) 343 j-- 344 } else { 345 // 2×2 diagonal block. 346 scale, xnorm, _ := impl.Dlaln2(false, 2, 1, smin, 1, t[(j-1)*ldt+j-1:], ldt, 347 1, 1, b[(j-1)*ldb+iv:], ldb, wr, 0, x[:3], 2) 348 // Scale X[0,0] and X[1,0] to avoid overflow 349 // when updating the right-hand side. 350 if xnorm > 1 { 351 beta := math.Max(norms[j-1], norms[j]) 352 if beta > bignum/xnorm { 353 x[0] /= xnorm 354 x[2] /= xnorm 355 scale /= xnorm 356 } 357 } 358 // Scale if necessary. 359 if scale != 1 { 360 bi.Dscal(ki+1, scale, b[iv:], ldb) 361 } 362 b[(j-1)*ldb+iv] = x[0] 363 b[j*ldb+iv] = x[2] 364 // Update right-hand side. 365 bi.Daxpy(j-1, -x[0], t[j-1:], ldt, b[iv:], ldb) 366 bi.Daxpy(j-1, -x[2], t[j:], ldt, b[iv:], ldb) 367 j -= 2 368 } 369 } 370 // Copy the vector x or Q*x to VR and normalize. 371 switch { 372 case howmny != lapack.EVAllMulQ: 373 // No back-transform: copy x to VR and normalize. 374 bi.Dcopy(ki+1, b[iv:], ldb, vr[is:], ldvr) 375 ii := bi.Idamax(ki+1, vr[is:], ldvr) 376 remax := 1 / math.Abs(vr[ii*ldvr+is]) 377 bi.Dscal(ki+1, remax, vr[is:], ldvr) 378 for k := ki + 1; k < n; k++ { 379 vr[k*ldvr+is] = 0 380 } 381 case nb == 1: 382 // Version 1: back-transform each vector with GEMV, Q*x. 383 if ki > 0 { 384 bi.Dgemv(blas.NoTrans, n, ki, 1, vr, ldvr, b[iv:], ldb, 385 b[ki*ldb+iv], vr[ki:], ldvr) 386 } 387 ii := bi.Idamax(n, vr[ki:], ldvr) 388 remax := 1 / math.Abs(vr[ii*ldvr+ki]) 389 bi.Dscal(n, remax, vr[ki:], ldvr) 390 default: 391 // Version 2: back-transform block of vectors with GEMM. 392 // Zero out below vector. 393 for k := ki + 1; k < n; k++ { 394 b[k*ldb+iv] = 0 395 } 396 iscomplex[iv] = ip 397 // Back-transform and normalization is done below. 398 } 399 } else { 400 // Complex right eigenvector. 401 402 // Initial solve 403 // [ ( T[ki-1,ki-1] T[ki-1,ki] ) - (wr + i*wi) ]*X = 0. 404 // [ ( T[ki, ki-1] T[ki, ki] ) ] 405 if math.Abs(t[(ki-1)*ldt+ki]) >= math.Abs(t[ki*ldt+ki-1]) { 406 b[(ki-1)*ldb+iv-1] = 1 407 b[ki*ldb+iv] = wi / t[(ki-1)*ldt+ki] 408 } else { 409 b[(ki-1)*ldb+iv-1] = -wi / t[ki*ldt+ki-1] 410 b[ki*ldb+iv] = 1 411 } 412 b[ki*ldb+iv-1] = 0 413 b[(ki-1)*ldb+iv] = 0 414 // Form right-hand side. 415 for k := 0; k < ki-1; k++ { 416 b[k*ldb+iv-1] = -b[(ki-1)*ldb+iv-1] * t[k*ldt+ki-1] 417 b[k*ldb+iv] = -b[ki*ldb+iv] * t[k*ldt+ki] 418 } 419 // Solve upper quasi-triangular system: 420 // [ T[0:ki-1,0:ki-1] - (wr+i*wi) ]*X = scale*(b1+i*b2) 421 for j := ki - 2; j >= 0; { 422 if j == 0 || t[j*ldt+j-1] == 0 { 423 // 1×1 diagonal block. 424 425 scale, xnorm, _ := impl.Dlaln2(false, 1, 2, smin, 1, t[j*ldt+j:], ldt, 426 1, 1, b[j*ldb+iv-1:], ldb, wr, wi, x[:2], 2) 427 // Scale X[0,0] and X[0,1] to avoid 428 // overflow when updating the right-hand side. 429 if xnorm > 1 && norms[j] > bignum/xnorm { 430 x[0] /= xnorm 431 x[1] /= xnorm 432 scale /= xnorm 433 } 434 // Scale if necessary. 435 if scale != 1 { 436 bi.Dscal(ki+1, scale, b[iv-1:], ldb) 437 bi.Dscal(ki+1, scale, b[iv:], ldb) 438 } 439 b[j*ldb+iv-1] = x[0] 440 b[j*ldb+iv] = x[1] 441 // Update the right-hand side. 442 bi.Daxpy(j, -x[0], t[j:], ldt, b[iv-1:], ldb) 443 bi.Daxpy(j, -x[1], t[j:], ldt, b[iv:], ldb) 444 j-- 445 } else { 446 // 2×2 diagonal block. 447 448 scale, xnorm, _ := impl.Dlaln2(false, 2, 2, smin, 1, t[(j-1)*ldt+j-1:], ldt, 449 1, 1, b[(j-1)*ldb+iv-1:], ldb, wr, wi, x[:], 2) 450 // Scale X to avoid overflow when updating 451 // the right-hand side. 452 if xnorm > 1 { 453 beta := math.Max(norms[j-1], norms[j]) 454 if beta > bignum/xnorm { 455 rec := 1 / xnorm 456 x[0] *= rec 457 x[1] *= rec 458 x[2] *= rec 459 x[3] *= rec 460 scale *= rec 461 } 462 } 463 // Scale if necessary. 464 if scale != 1 { 465 bi.Dscal(ki+1, scale, b[iv-1:], ldb) 466 bi.Dscal(ki+1, scale, b[iv:], ldb) 467 } 468 b[(j-1)*ldb+iv-1] = x[0] 469 b[(j-1)*ldb+iv] = x[1] 470 b[j*ldb+iv-1] = x[2] 471 b[j*ldb+iv] = x[3] 472 // Update the right-hand side. 473 bi.Daxpy(j-1, -x[0], t[j-1:], ldt, b[iv-1:], ldb) 474 bi.Daxpy(j-1, -x[1], t[j-1:], ldt, b[iv:], ldb) 475 bi.Daxpy(j-1, -x[2], t[j:], ldt, b[iv-1:], ldb) 476 bi.Daxpy(j-1, -x[3], t[j:], ldt, b[iv:], ldb) 477 j -= 2 478 } 479 } 480 481 // Copy the vector x or Q*x to VR and normalize. 482 switch { 483 case howmny != lapack.EVAllMulQ: 484 // No back-transform: copy x to VR and normalize. 485 bi.Dcopy(ki+1, b[iv-1:], ldb, vr[is-1:], ldvr) 486 bi.Dcopy(ki+1, b[iv:], ldb, vr[is:], ldvr) 487 emax := 0.0 488 for k := 0; k <= ki; k++ { 489 emax = math.Max(emax, math.Abs(vr[k*ldvr+is-1])+math.Abs(vr[k*ldvr+is])) 490 } 491 remax := 1 / emax 492 bi.Dscal(ki+1, remax, vr[is-1:], ldvr) 493 bi.Dscal(ki+1, remax, vr[is:], ldvr) 494 for k := ki + 1; k < n; k++ { 495 vr[k*ldvr+is-1] = 0 496 vr[k*ldvr+is] = 0 497 } 498 case nb == 1: 499 // Version 1: back-transform each vector with GEMV, Q*x. 500 if ki-1 > 0 { 501 bi.Dgemv(blas.NoTrans, n, ki-1, 1, vr, ldvr, b[iv-1:], ldb, 502 b[(ki-1)*ldb+iv-1], vr[ki-1:], ldvr) 503 bi.Dgemv(blas.NoTrans, n, ki-1, 1, vr, ldvr, b[iv:], ldb, 504 b[ki*ldb+iv], vr[ki:], ldvr) 505 } else { 506 bi.Dscal(n, b[(ki-1)*ldb+iv-1], vr[ki-1:], ldvr) 507 bi.Dscal(n, b[ki*ldb+iv], vr[ki:], ldvr) 508 } 509 emax := 0.0 510 for k := 0; k < n; k++ { 511 emax = math.Max(emax, math.Abs(vr[k*ldvr+ki-1])+math.Abs(vr[k*ldvr+ki])) 512 } 513 remax := 1 / emax 514 bi.Dscal(n, remax, vr[ki-1:], ldvr) 515 bi.Dscal(n, remax, vr[ki:], ldvr) 516 default: 517 // Version 2: back-transform block of vectors with GEMM. 518 // Zero out below vector. 519 for k := ki + 1; k < n; k++ { 520 b[k*ldb+iv-1] = 0 521 b[k*ldb+iv] = 0 522 } 523 iscomplex[iv-1] = -ip 524 iscomplex[iv] = ip 525 iv-- 526 // Back-transform and normalization is done below. 527 } 528 } 529 if nb > 1 { 530 // Blocked version of back-transform. 531 532 // For complex case, ki2 includes both vectors (ki-1 and ki). 533 ki2 := ki 534 if ip != 0 { 535 ki2-- 536 } 537 // Columns iv:nb of b are valid vectors. 538 // When the number of vectors stored reaches nb-1 or nb, 539 // or if this was last vector, do the Gemm. 540 if iv < 2 || ki2 == 0 { 541 bi.Dgemm(blas.NoTrans, blas.NoTrans, n, nb-iv, ki2+nb-iv, 542 1, vr, ldvr, b[iv:], ldb, 543 0, b[nb+iv:], ldb) 544 // Normalize vectors. 545 var remax float64 546 for k := iv; k < nb; k++ { 547 if iscomplex[k] == 0 { 548 // Real eigenvector. 549 ii := bi.Idamax(n, b[nb+k:], ldb) 550 remax = 1 / math.Abs(b[ii*ldb+nb+k]) 551 } else if iscomplex[k] == 1 { 552 // First eigenvector of conjugate pair. 553 emax := 0.0 554 for ii := 0; ii < n; ii++ { 555 emax = math.Max(emax, math.Abs(b[ii*ldb+nb+k])+math.Abs(b[ii*ldb+nb+k+1])) 556 } 557 remax = 1 / emax 558 // Second eigenvector of conjugate pair 559 // will reuse this value of remax. 560 } 561 bi.Dscal(n, remax, b[nb+k:], ldb) 562 } 563 impl.Dlacpy(blas.All, n, nb-iv, b[nb+iv:], ldb, vr[ki2:], ldvr) 564 iv = nb - 1 565 } else { 566 iv-- 567 } 568 } 569 is-- 570 if ip != 0 { 571 is-- 572 } 573 } 574 575 if side == lapack.EVRight { 576 return m 577 } 578 579 leftev: 580 // Compute left eigenvectors. 581 582 // For complex left vector, iv is for real part and iv+1 for complex 583 // part. Non-blocked version always uses iv=0. Blocked version starts 584 // with iv=0, goes up to nb-2 or nb-1. 585 iv = 0 586 ip = 0 587 is = 0 588 for ki := 0; ki < n; ki++ { 589 if ip == 1 { 590 // Previous iteration ki-1 was first of conjugate pair, 591 // so this ki is second of conjugate pair. 592 ip = -1 593 continue 594 } 595 596 if ki == n-1 || t[(ki+1)*ldt+ki] == 0 { 597 // Last column or zero on sub-diagonal, so this ki must 598 // be real eigenvalue. 599 ip = 0 600 } else { 601 // Non-zero on sub-diagonal, so this ki is first of 602 // conjugate pair. 603 ip = 1 604 } 605 if howmny == lapack.EVSelected && !selected[ki] { 606 continue 607 } 608 609 // Compute the ki-th eigenvalue (wr,wi). 610 wr := t[ki*ldt+ki] 611 var wi float64 612 if ip != 0 { 613 wi = math.Sqrt(math.Abs(t[ki*ldt+ki+1])) * math.Sqrt(math.Abs(t[(ki+1)*ldt+ki])) 614 } 615 smin := math.Max(ulp*(math.Abs(wr)+math.Abs(wi)), smlnum) 616 617 if ip == 0 { 618 // Real left eigenvector. 619 620 b[ki*ldb+iv] = 1 621 // Form right-hand side. 622 for k := ki + 1; k < n; k++ { 623 b[k*ldb+iv] = -t[ki*ldt+k] 624 } 625 // Solve transposed quasi-triangular system: 626 // [ T[ki+1:n,ki+1:n] - wr ]ᵀ * X = scale*b 627 vmax := 1.0 628 vcrit := bignum 629 for j := ki + 1; j < n; { 630 if j == n-1 || t[(j+1)*ldt+j] == 0 { 631 // 1×1 diagonal block. 632 633 // Scale if necessary to avoid overflow 634 // when forming the right-hand side. 635 if norms[j] > vcrit { 636 rec := 1 / vmax 637 bi.Dscal(n-ki, rec, b[ki*ldb+iv:], ldb) 638 vmax = 1 639 } 640 b[j*ldb+iv] -= bi.Ddot(j-ki-1, t[(ki+1)*ldt+j:], ldt, b[(ki+1)*ldb+iv:], ldb) 641 // Solve [ T[j,j] - wr ]ᵀ * X = b. 642 scale, _, _ := impl.Dlaln2(false, 1, 1, smin, 1, t[j*ldt+j:], ldt, 643 1, 1, b[j*ldb+iv:], ldb, wr, 0, x[:1], 2) 644 // Scale if necessary. 645 if scale != 1 { 646 bi.Dscal(n-ki, scale, b[ki*ldb+iv:], ldb) 647 } 648 b[j*ldb+iv] = x[0] 649 vmax = math.Max(math.Abs(b[j*ldb+iv]), vmax) 650 vcrit = bignum / vmax 651 j++ 652 } else { 653 // 2×2 diagonal block. 654 655 // Scale if necessary to avoid overflow 656 // when forming the right-hand side. 657 beta := math.Max(norms[j], norms[j+1]) 658 if beta > vcrit { 659 bi.Dscal(n-ki, 1/vmax, b[ki*ldb+iv:], ldb) 660 vmax = 1 661 } 662 b[j*ldb+iv] -= bi.Ddot(j-ki-1, t[(ki+1)*ldt+j:], ldt, b[(ki+1)*ldb+iv:], ldb) 663 b[(j+1)*ldb+iv] -= bi.Ddot(j-ki-1, t[(ki+1)*ldt+j+1:], ldt, b[(ki+1)*ldb+iv:], ldb) 664 // Solve 665 // [ T[j,j]-wr T[j,j+1] ]ᵀ * X = scale*[ b1 ] 666 // [ T[j+1,j] T[j+1,j+1]-wr ] [ b2 ] 667 scale, _, _ := impl.Dlaln2(true, 2, 1, smin, 1, t[j*ldt+j:], ldt, 668 1, 1, b[j*ldb+iv:], ldb, wr, 0, x[:3], 2) 669 // Scale if necessary. 670 if scale != 1 { 671 bi.Dscal(n-ki, scale, b[ki*ldb+iv:], ldb) 672 } 673 b[j*ldb+iv] = x[0] 674 b[(j+1)*ldb+iv] = x[2] 675 vmax = math.Max(vmax, math.Max(math.Abs(b[j*ldb+iv]), math.Abs(b[(j+1)*ldb+iv]))) 676 vcrit = bignum / vmax 677 j += 2 678 } 679 } 680 // Copy the vector x or Q*x to VL and normalize. 681 switch { 682 case howmny != lapack.EVAllMulQ: 683 // No back-transform: copy x to VL and normalize. 684 bi.Dcopy(n-ki, b[ki*ldb+iv:], ldb, vl[ki*ldvl+is:], ldvl) 685 ii := bi.Idamax(n-ki, vl[ki*ldvl+is:], ldvl) + ki 686 remax := 1 / math.Abs(vl[ii*ldvl+is]) 687 bi.Dscal(n-ki, remax, vl[ki*ldvl+is:], ldvl) 688 for k := 0; k < ki; k++ { 689 vl[k*ldvl+is] = 0 690 } 691 case nb == 1: 692 // Version 1: back-transform each vector with Gemv, Q*x. 693 if n-ki-1 > 0 { 694 bi.Dgemv(blas.NoTrans, n, n-ki-1, 695 1, vl[ki+1:], ldvl, b[(ki+1)*ldb+iv:], ldb, 696 b[ki*ldb+iv], vl[ki:], ldvl) 697 } 698 ii := bi.Idamax(n, vl[ki:], ldvl) 699 remax := 1 / math.Abs(vl[ii*ldvl+ki]) 700 bi.Dscal(n, remax, vl[ki:], ldvl) 701 default: 702 // Version 2: back-transform block of vectors with Gemm 703 // zero out above vector. 704 for k := 0; k < ki; k++ { 705 b[k*ldb+iv] = 0 706 } 707 iscomplex[iv] = ip 708 // Back-transform and normalization is done below. 709 } 710 } else { 711 // Complex left eigenvector. 712 713 // Initial solve: 714 // [ [ T[ki,ki] T[ki,ki+1] ]ᵀ - (wr - i* wi) ]*X = 0. 715 // [ [ T[ki+1,ki] T[ki+1,ki+1] ] ] 716 if math.Abs(t[ki*ldt+ki+1]) >= math.Abs(t[(ki+1)*ldt+ki]) { 717 b[ki*ldb+iv] = wi / t[ki*ldt+ki+1] 718 b[(ki+1)*ldb+iv+1] = 1 719 } else { 720 b[ki*ldb+iv] = 1 721 b[(ki+1)*ldb+iv+1] = -wi / t[(ki+1)*ldt+ki] 722 } 723 b[(ki+1)*ldb+iv] = 0 724 b[ki*ldb+iv+1] = 0 725 // Form right-hand side. 726 for k := ki + 2; k < n; k++ { 727 b[k*ldb+iv] = -b[ki*ldb+iv] * t[ki*ldt+k] 728 b[k*ldb+iv+1] = -b[(ki+1)*ldb+iv+1] * t[(ki+1)*ldt+k] 729 } 730 // Solve transposed quasi-triangular system: 731 // [ T[ki+2:n,ki+2:n]ᵀ - (wr-i*wi) ]*X = b1+i*b2 732 vmax := 1.0 733 vcrit := bignum 734 for j := ki + 2; j < n; { 735 if j == n-1 || t[(j+1)*ldt+j] == 0 { 736 // 1×1 diagonal block. 737 738 // Scale if necessary to avoid overflow 739 // when forming the right-hand side elements. 740 if norms[j] > vcrit { 741 rec := 1 / vmax 742 bi.Dscal(n-ki, rec, b[ki*ldb+iv:], ldb) 743 bi.Dscal(n-ki, rec, b[ki*ldb+iv+1:], ldb) 744 vmax = 1 745 } 746 b[j*ldb+iv] -= bi.Ddot(j-ki-2, t[(ki+2)*ldt+j:], ldt, b[(ki+2)*ldb+iv:], ldb) 747 b[j*ldb+iv+1] -= bi.Ddot(j-ki-2, t[(ki+2)*ldt+j:], ldt, b[(ki+2)*ldb+iv+1:], ldb) 748 // Solve [ T[j,j]-(wr-i*wi) ]*(X11+i*X12) = b1+i*b2. 749 scale, _, _ := impl.Dlaln2(false, 1, 2, smin, 1, t[j*ldt+j:], ldt, 750 1, 1, b[j*ldb+iv:], ldb, wr, -wi, x[:2], 2) 751 // Scale if necessary. 752 if scale != 1 { 753 bi.Dscal(n-ki, scale, b[ki*ldb+iv:], ldb) 754 bi.Dscal(n-ki, scale, b[ki*ldb+iv+1:], ldb) 755 } 756 b[j*ldb+iv] = x[0] 757 b[j*ldb+iv+1] = x[1] 758 vmax = math.Max(vmax, math.Max(math.Abs(b[j*ldb+iv]), math.Abs(b[j*ldb+iv+1]))) 759 vcrit = bignum / vmax 760 j++ 761 } else { 762 // 2×2 diagonal block. 763 764 // Scale if necessary to avoid overflow 765 // when forming the right-hand side elements. 766 if math.Max(norms[j], norms[j+1]) > vcrit { 767 rec := 1 / vmax 768 bi.Dscal(n-ki, rec, b[ki*ldb+iv:], ldb) 769 bi.Dscal(n-ki, rec, b[ki*ldb+iv+1:], ldb) 770 vmax = 1 771 } 772 b[j*ldb+iv] -= bi.Ddot(j-ki-2, t[(ki+2)*ldt+j:], ldt, b[(ki+2)*ldb+iv:], ldb) 773 b[j*ldb+iv+1] -= bi.Ddot(j-ki-2, t[(ki+2)*ldt+j:], ldt, b[(ki+2)*ldb+iv+1:], ldb) 774 b[(j+1)*ldb+iv] -= bi.Ddot(j-ki-2, t[(ki+2)*ldt+j+1:], ldt, b[(ki+2)*ldb+iv:], ldb) 775 b[(j+1)*ldb+iv+1] -= bi.Ddot(j-ki-2, t[(ki+2)*ldt+j+1:], ldt, b[(ki+2)*ldb+iv+1:], ldb) 776 // Solve 2×2 complex linear equation 777 // [ [T[j,j] T[j,j+1] ]ᵀ - (wr-i*wi)*I ]*X = scale*b 778 // [ [T[j+1,j] T[j+1,j+1]] ] 779 scale, _, _ := impl.Dlaln2(true, 2, 2, smin, 1, t[j*ldt+j:], ldt, 780 1, 1, b[j*ldb+iv:], ldb, wr, -wi, x[:], 2) 781 // Scale if necessary. 782 if scale != 1 { 783 bi.Dscal(n-ki, scale, b[ki*ldb+iv:], ldb) 784 bi.Dscal(n-ki, scale, b[ki*ldb+iv+1:], ldb) 785 } 786 b[j*ldb+iv] = x[0] 787 b[j*ldb+iv+1] = x[1] 788 b[(j+1)*ldb+iv] = x[2] 789 b[(j+1)*ldb+iv+1] = x[3] 790 vmax01 := math.Max(math.Abs(x[0]), math.Abs(x[1])) 791 vmax23 := math.Max(math.Abs(x[2]), math.Abs(x[3])) 792 vmax = math.Max(vmax, math.Max(vmax01, vmax23)) 793 vcrit = bignum / vmax 794 j += 2 795 } 796 } 797 // Copy the vector x or Q*x to VL and normalize. 798 switch { 799 case howmny != lapack.EVAllMulQ: 800 // No back-transform: copy x to VL and normalize. 801 bi.Dcopy(n-ki, b[ki*ldb+iv:], ldb, vl[ki*ldvl+is:], ldvl) 802 bi.Dcopy(n-ki, b[ki*ldb+iv+1:], ldb, vl[ki*ldvl+is+1:], ldvl) 803 emax := 0.0 804 for k := ki; k < n; k++ { 805 emax = math.Max(emax, math.Abs(vl[k*ldvl+is])+math.Abs(vl[k*ldvl+is+1])) 806 } 807 remax := 1 / emax 808 bi.Dscal(n-ki, remax, vl[ki*ldvl+is:], ldvl) 809 bi.Dscal(n-ki, remax, vl[ki*ldvl+is+1:], ldvl) 810 for k := 0; k < ki; k++ { 811 vl[k*ldvl+is] = 0 812 vl[k*ldvl+is+1] = 0 813 } 814 case nb == 1: 815 // Version 1: back-transform each vector with GEMV, Q*x. 816 if n-ki-2 > 0 { 817 bi.Dgemv(blas.NoTrans, n, n-ki-2, 818 1, vl[ki+2:], ldvl, b[(ki+2)*ldb+iv:], ldb, 819 b[ki*ldb+iv], vl[ki:], ldvl) 820 bi.Dgemv(blas.NoTrans, n, n-ki-2, 821 1, vl[ki+2:], ldvl, b[(ki+2)*ldb+iv+1:], ldb, 822 b[(ki+1)*ldb+iv+1], vl[ki+1:], ldvl) 823 } else { 824 bi.Dscal(n, b[ki*ldb+iv], vl[ki:], ldvl) 825 bi.Dscal(n, b[(ki+1)*ldb+iv+1], vl[ki+1:], ldvl) 826 } 827 emax := 0.0 828 for k := 0; k < n; k++ { 829 emax = math.Max(emax, math.Abs(vl[k*ldvl+ki])+math.Abs(vl[k*ldvl+ki+1])) 830 } 831 remax := 1 / emax 832 bi.Dscal(n, remax, vl[ki:], ldvl) 833 bi.Dscal(n, remax, vl[ki+1:], ldvl) 834 default: 835 // Version 2: back-transform block of vectors with GEMM. 836 // Zero out above vector. 837 // Could go from ki-nv+1 to ki-1. 838 for k := 0; k < ki; k++ { 839 b[k*ldb+iv] = 0 840 b[k*ldb+iv+1] = 0 841 } 842 iscomplex[iv] = ip 843 iscomplex[iv+1] = -ip 844 iv++ 845 // Back-transform and normalization is done below. 846 } 847 } 848 if nb > 1 { 849 // Blocked version of back-transform. 850 // For complex case, ki2 includes both vectors ki and ki+1. 851 ki2 := ki 852 if ip != 0 { 853 ki2++ 854 } 855 // Columns [0:iv] of work are valid vectors. When the 856 // number of vectors stored reaches nb-1 or nb, or if 857 // this was last vector, do the Gemm. 858 if iv >= nb-2 || ki2 == n-1 { 859 bi.Dgemm(blas.NoTrans, blas.NoTrans, n, iv+1, n-ki2+iv, 860 1, vl[ki2-iv:], ldvl, b[(ki2-iv)*ldb:], ldb, 861 0, b[nb:], ldb) 862 // Normalize vectors. 863 var remax float64 864 for k := 0; k <= iv; k++ { 865 if iscomplex[k] == 0 { 866 // Real eigenvector. 867 ii := bi.Idamax(n, b[nb+k:], ldb) 868 remax = 1 / math.Abs(b[ii*ldb+nb+k]) 869 } else if iscomplex[k] == 1 { 870 // First eigenvector of conjugate pair. 871 emax := 0.0 872 for ii := 0; ii < n; ii++ { 873 emax = math.Max(emax, math.Abs(b[ii*ldb+nb+k])+math.Abs(b[ii*ldb+nb+k+1])) 874 } 875 remax = 1 / emax 876 // Second eigenvector of conjugate pair 877 // will reuse this value of remax. 878 } 879 bi.Dscal(n, remax, b[nb+k:], ldb) 880 } 881 impl.Dlacpy(blas.All, n, iv+1, b[nb:], ldb, vl[ki2-iv:], ldvl) 882 iv = 0 883 } else { 884 iv++ 885 } 886 } 887 is++ 888 if ip != 0 { 889 is++ 890 } 891 } 892 893 return m 894 }