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.
10 "gonum.org/v1/gonum/blas"
11 "gonum.org/v1/gonum/blas/blas64"
12 "gonum.org/v1/gonum/lapack"
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
19 // as computed by Dhseqr.
21 // The right eigenvector x of T corresponding to an
22 // eigenvalue λ is defined by
24 // and the left eigenvector is defined by
26 // where y^H is the conjugate transpose of y.
28 // The eigenvalues are read directly from the diagonal blocks of T.
30 // This routine returns the matrices X and/or Y of right and left eigenvectors
31 // of T, or the products Q*X and/or Q*Y, where Q is an input matrix. If Q is the
32 // orthogonal factor that reduces a matrix A to Schur form T, then Q*X and Q*Y
33 // are the matrices of right and left eigenvectors of A.
35 // If side == lapack.RightEV, only right eigenvectors will be computed.
36 // If side == lapack.LeftEV, only left eigenvectors will be computed.
37 // If side == lapack.RightLeftEV, both right and left eigenvectors will be computed.
38 // For other values of side, Dtrevc3 will panic.
40 // If howmny == lapack.AllEV, all right and/or left eigenvectors will be
42 // If howmny == lapack.AllEVMulQ, all right and/or left eigenvectors will be
43 // computed and multiplied from left by the matrices in VR and/or VL.
44 // If howmny == lapack.SelectedEV, right and/or left eigenvectors will be
45 // computed as indicated by selected.
46 // For other values of howmny, Dtrevc3 will panic.
48 // selected specifies which eigenvectors will be computed. It must have length n
49 // if howmny == lapack.SelectedEV, and it is not referenced otherwise.
50 // If w_j is a real eigenvalue, the corresponding real eigenvector will be
51 // computed if selected[j] is true.
52 // If w_j and w_{j+1} are the real and imaginary parts of a complex eigenvalue,
53 // the corresponding complex eigenvector is computed if either selected[j] or
54 // selected[j+1] is true, and on return selected[j] will be set to true and
55 // selected[j+1] will be set to false.
57 // VL and VR are n×mm matrices. If howmny is lapack.AllEV or
58 // lapack.AllEVMulQ, mm must be at least n. If howmny ==
59 // lapack.SelectedEV, mm must be large enough to store the selected
60 // eigenvectors. Each selected real eigenvector occupies one column and each
61 // selected complex eigenvector occupies two columns. If mm is not sufficiently
62 // large, Dtrevc3 will panic.
64 // On entry, if howmny == lapack.AllEVMulQ, it is assumed that VL (if side
65 // is lapack.LeftEV or lapack.RightLeftEV) contains an n×n matrix QL,
66 // and that VR (if side is lapack.LeftEV or lapack.RightLeftEV) contains
67 // an n×n matrix QR. QL and QR are typically the orthogonal matrix Q of Schur
68 // vectors returned by Dhseqr.
70 // On return, if side is lapack.LeftEV or lapack.RightLeftEV,
72 // if howmny == lapack.AllEV, the matrix Y of left eigenvectors of T,
73 // if howmny == lapack.AllEVMulQ, the matrix Q*Y,
74 // if howmny == lapack.SelectedEV, the left eigenvectors of T specified by
75 // selected, stored consecutively in the
76 // columns of VL, in the same order as their
78 // VL is not referenced if side == lapack.RightEV.
80 // On return, if side is lapack.RightEV or lapack.RightLeftEV,
82 // if howmny == lapack.AllEV, the matrix X of right eigenvectors of T,
83 // if howmny == lapack.AllEVMulQ, the matrix Q*X,
84 // if howmny == lapack.SelectedEV, the left eigenvectors of T specified by
85 // selected, stored consecutively in the
86 // columns of VR, in the same order as their
88 // VR is not referenced if side == lapack.LeftEV.
90 // Complex eigenvectors corresponding to a complex eigenvalue are stored in VL
91 // and VR in two consecutive columns, the first holding the real part, and the
92 // second the imaginary part.
94 // Each eigenvector will be normalized so that the element of largest magnitude
95 // has magnitude 1. Here the magnitude of a complex number (x,y) is taken to be
98 // work must have length at least lwork and lwork must be at least max(1,3*n),
99 // otherwise Dtrevc3 will panic. For optimum performance, lwork should be at
100 // least n+2*n*nb, where nb is the optimal blocksize.
102 // If lwork == -1, instead of performing Dtrevc3, the function only estimates
103 // the optimal workspace size based on n and stores it into work[0].
105 // Dtrevc3 returns the number of columns in VL and/or VR actually used to store
108 // Dtrevc3 is an internal routine. It is exported for testing purposes.
109 func (impl Implementation) Dtrevc3(side lapack.EVSide, howmny lapack.HowMany, selected []bool, n int, t []float64, ldt int, vl []float64, ldvl int, vr []float64, ldvr int, mm int, work []float64, lwork int) (m int) {
113 case lapack.RightEV, lapack.LeftEV, lapack.RightLeftEV:
118 case lapack.AllEV, lapack.AllEVMulQ, lapack.SelectedEV:
123 case len(work) < lwork:
125 case lwork < max(1, 3*n) && lwork != -1:
129 if howmny == lapack.SelectedEV {
130 if len(selected) != n {
131 panic("lapack: bad selected length")
133 // Set m to the number of columns required to store the
134 // selected eigenvectors, and standardize the slice
137 if j == n-1 || t[(j+1)*ldt+j] == 0 {
138 // Diagonal 1×1 block corresponding to a
145 // Diagonal 2×2 block corresponding to a
146 // complex eigenvalue.
147 if selected[j] || selected[j+1] {
149 selected[j+1] = false
159 panic("lapack: insufficient number of columns")
161 checkMatrix(n, n, t, ldt)
162 if (side == lapack.RightEV || side == lapack.RightLeftEV) && m > 0 {
163 checkMatrix(n, m, vr, ldvr)
165 if (side == lapack.LeftEV || side == lapack.RightLeftEV) && m > 0 {
166 checkMatrix(n, m, vl, ldvl)
170 // Quick return if possible.
180 nb := impl.Ilaenv(1, "DTREVC", string(side)+string(howmny), n, -1, -1, -1)
182 // Quick return in case of a workspace query.
184 work[0] = float64(n + 2*n*nb)
188 // Use blocked version of back-transformation if sufficient workspace.
189 // Zero-out the workspace to avoid potential NaN propagation.
190 if howmny == lapack.AllEVMulQ && lwork >= n+2*n*nbmin {
191 nb = min((lwork-n)/(2*n), nbmax)
192 impl.Dlaset(blas.All, n, 1+2*nb, 0, 0, work[:n+2*nb*n], 1+2*nb)
197 // Set the constants to control overflow.
199 smlnum := float64(n) / ulp * dlamchS
200 bignum := (1 - ulp) / smlnum
202 // Split work into a vector of column norms and an n×2*nb matrix b.
205 b := work[n : n+n*ldb]
207 // Compute 1-norm of each column of strictly upper triangular part of T
208 // to control overflow in triangular solver.
210 for j := 1; j < n; j++ {
212 for i := 0; i < j; i++ {
213 cn += math.Abs(t[i*ldt+j])
218 bi := blas64.Implementation()
223 iv int // Index of column in current block.
226 // ip is used below to specify the real or complex eigenvalue:
227 // ip == 0, real eigenvalue,
228 // 1, first of conjugate complex pair (wr,wi),
229 // -1, second of conjugate complex pair (wr,wi).
231 iscomplex [nbmax]int // Stores ip for each column in current block.
234 if side == lapack.LeftEV {
238 // Compute right eigenvectors.
240 // For complex right vector, iv-1 is for real part and iv for complex
241 // part. Non-blocked version always uses iv=1, blocked version starts
242 // with iv=nb-1 and goes down to 0 or 1.
246 for ki := n - 1; ki >= 0; ki-- {
248 // Previous iteration (ki+1) was second of
249 // conjugate pair, so this ki is first of
255 if ki == 0 || t[ki*ldt+ki-1] == 0 {
256 // Last column or zero on sub-diagonal, so this
257 // ki must be real eigenvalue.
260 // Non-zero on sub-diagonal, so this ki is
261 // second of conjugate pair.
265 if howmny == lapack.SelectedEV {
270 } else if !selected[ki-1] {
275 // Compute the ki-th eigenvalue (wr,wi).
279 wi = math.Sqrt(math.Abs(t[ki*ldt+ki-1])) * math.Sqrt(math.Abs(t[(ki-1)*ldt+ki]))
281 smin := math.Max(ulp*(math.Abs(wr)+math.Abs(wi)), smlnum)
284 // Real right eigenvector.
287 // Form right-hand side.
288 for k := 0; k < ki; k++ {
289 b[k*ldb+iv] = -t[k*ldt+ki]
291 // Solve upper quasi-triangular system:
292 // [ T[0:ki,0:ki] - wr ]*X = scale*b.
293 for j := ki - 1; j >= 0; {
294 if j == 0 || t[j*ldt+j-1] == 0 {
295 // 1×1 diagonal block.
296 scale, xnorm, _ := impl.Dlaln2(false, 1, 1, smin, 1, t[j*ldt+j:], ldt,
297 1, 1, b[j*ldb+iv:], ldb, wr, 0, x[:1], 2)
298 // Scale X[0,0] to avoid overflow when updating the
300 if xnorm > 1 && norms[j] > bignum/xnorm {
304 // Scale if necessary.
306 bi.Dscal(ki+1, scale, b[iv:], ldb)
309 // Update right-hand side.
310 bi.Daxpy(j, -x[0], t[j:], ldt, b[iv:], ldb)
313 // 2×2 diagonal block.
314 scale, xnorm, _ := impl.Dlaln2(false, 2, 1, smin, 1, t[(j-1)*ldt+j-1:], ldt,
315 1, 1, b[(j-1)*ldb+iv:], ldb, wr, 0, x[:3], 2)
316 // Scale X[0,0] and X[1,0] to avoid overflow
317 // when updating the right-hand side.
319 beta := math.Max(norms[j-1], norms[j])
320 if beta > bignum/xnorm {
326 // Scale if necessary.
328 bi.Dscal(ki+1, scale, b[iv:], ldb)
330 b[(j-1)*ldb+iv] = x[0]
332 // Update right-hand side.
333 bi.Daxpy(j-1, -x[0], t[j-1:], ldt, b[iv:], ldb)
334 bi.Daxpy(j-1, -x[2], t[j:], ldt, b[iv:], ldb)
338 // Copy the vector x or Q*x to VR and normalize.
340 case howmny != lapack.AllEVMulQ:
341 // No back-transform: copy x to VR and normalize.
342 bi.Dcopy(ki+1, b[iv:], ldb, vr[is:], ldvr)
343 ii := bi.Idamax(ki+1, vr[is:], ldvr)
344 remax := 1 / math.Abs(vr[ii*ldvr+is])
345 bi.Dscal(ki+1, remax, vr[is:], ldvr)
346 for k := ki + 1; k < n; k++ {
350 // Version 1: back-transform each vector with GEMV, Q*x.
352 bi.Dgemv(blas.NoTrans, n, ki, 1, vr, ldvr, b[iv:], ldb,
353 b[ki*ldb+iv], vr[ki:], ldvr)
355 ii := bi.Idamax(n, vr[ki:], ldvr)
356 remax := 1 / math.Abs(vr[ii*ldvr+ki])
357 bi.Dscal(n, remax, vr[ki:], ldvr)
359 // Version 2: back-transform block of vectors with GEMM.
360 // Zero out below vector.
361 for k := ki + 1; k < n; k++ {
365 // Back-transform and normalization is done below.
368 // Complex right eigenvector.
371 // [ ( T[ki-1,ki-1] T[ki-1,ki] ) - (wr + i*wi) ]*X = 0.
372 // [ ( T[ki, ki-1] T[ki, ki] ) ]
373 if math.Abs(t[(ki-1)*ldt+ki]) >= math.Abs(t[ki*ldt+ki-1]) {
374 b[(ki-1)*ldb+iv-1] = 1
375 b[ki*ldb+iv] = wi / t[(ki-1)*ldt+ki]
377 b[(ki-1)*ldb+iv-1] = -wi / t[ki*ldt+ki-1]
382 // Form right-hand side.
383 for k := 0; k < ki-1; k++ {
384 b[k*ldb+iv-1] = -b[(ki-1)*ldb+iv-1] * t[k*ldt+ki-1]
385 b[k*ldb+iv] = -b[ki*ldb+iv] * t[k*ldt+ki]
387 // Solve upper quasi-triangular system:
388 // [ T[0:ki-1,0:ki-1] - (wr+i*wi) ]*X = scale*(b1+i*b2)
389 for j := ki - 2; j >= 0; {
390 if j == 0 || t[j*ldt+j-1] == 0 {
391 // 1×1 diagonal block.
393 scale, xnorm, _ := impl.Dlaln2(false, 1, 2, smin, 1, t[j*ldt+j:], ldt,
394 1, 1, b[j*ldb+iv-1:], ldb, wr, wi, x[:2], 2)
395 // Scale X[0,0] and X[0,1] to avoid
396 // overflow when updating the right-hand side.
397 if xnorm > 1 && norms[j] > bignum/xnorm {
402 // Scale if necessary.
404 bi.Dscal(ki+1, scale, b[iv-1:], ldb)
405 bi.Dscal(ki+1, scale, b[iv:], ldb)
409 // Update the right-hand side.
410 bi.Daxpy(j, -x[0], t[j:], ldt, b[iv-1:], ldb)
411 bi.Daxpy(j, -x[1], t[j:], ldt, b[iv:], ldb)
414 // 2×2 diagonal block.
416 scale, xnorm, _ := impl.Dlaln2(false, 2, 2, smin, 1, t[(j-1)*ldt+j-1:], ldt,
417 1, 1, b[(j-1)*ldb+iv-1:], ldb, wr, wi, x[:], 2)
418 // Scale X to avoid overflow when updating
419 // the right-hand side.
421 beta := math.Max(norms[j-1], norms[j])
422 if beta > bignum/xnorm {
431 // Scale if necessary.
433 bi.Dscal(ki+1, scale, b[iv-1:], ldb)
434 bi.Dscal(ki+1, scale, b[iv:], ldb)
436 b[(j-1)*ldb+iv-1] = x[0]
437 b[(j-1)*ldb+iv] = x[1]
440 // Update the right-hand side.
441 bi.Daxpy(j-1, -x[0], t[j-1:], ldt, b[iv-1:], ldb)
442 bi.Daxpy(j-1, -x[1], t[j-1:], ldt, b[iv:], ldb)
443 bi.Daxpy(j-1, -x[2], t[j:], ldt, b[iv-1:], ldb)
444 bi.Daxpy(j-1, -x[3], t[j:], ldt, b[iv:], ldb)
449 // Copy the vector x or Q*x to VR and normalize.
451 case howmny != lapack.AllEVMulQ:
452 // No back-transform: copy x to VR and normalize.
453 bi.Dcopy(ki+1, b[iv-1:], ldb, vr[is-1:], ldvr)
454 bi.Dcopy(ki+1, b[iv:], ldb, vr[is:], ldvr)
456 for k := 0; k <= ki; k++ {
457 emax = math.Max(emax, math.Abs(vr[k*ldvr+is-1])+math.Abs(vr[k*ldvr+is]))
460 bi.Dscal(ki+1, remax, vr[is-1:], ldvr)
461 bi.Dscal(ki+1, remax, vr[is:], ldvr)
462 for k := ki + 1; k < n; k++ {
467 // Version 1: back-transform each vector with GEMV, Q*x.
469 bi.Dgemv(blas.NoTrans, n, ki-1, 1, vr, ldvr, b[iv-1:], ldb,
470 b[(ki-1)*ldb+iv-1], vr[ki-1:], ldvr)
471 bi.Dgemv(blas.NoTrans, n, ki-1, 1, vr, ldvr, b[iv:], ldb,
472 b[ki*ldb+iv], vr[ki:], ldvr)
474 bi.Dscal(n, b[(ki-1)*ldb+iv-1], vr[ki-1:], ldvr)
475 bi.Dscal(n, b[ki*ldb+iv], vr[ki:], ldvr)
478 for k := 0; k < n; k++ {
479 emax = math.Max(emax, math.Abs(vr[k*ldvr+ki-1])+math.Abs(vr[k*ldvr+ki]))
482 bi.Dscal(n, remax, vr[ki-1:], ldvr)
483 bi.Dscal(n, remax, vr[ki:], ldvr)
485 // Version 2: back-transform block of vectors with GEMM.
486 // Zero out below vector.
487 for k := ki + 1; k < n; k++ {
491 iscomplex[iv-1] = -ip
494 // Back-transform and normalization is done below.
498 // Blocked version of back-transform.
500 // For complex case, ki2 includes both vectors (ki-1 and ki).
505 // Columns iv:nb of b are valid vectors.
506 // When the number of vectors stored reaches nb-1 or nb,
507 // or if this was last vector, do the Gemm.
508 if iv < 2 || ki2 == 0 {
509 bi.Dgemm(blas.NoTrans, blas.NoTrans, n, nb-iv, ki2+nb-iv,
510 1, vr, ldvr, b[iv:], ldb,
512 // Normalize vectors.
514 for k := iv; k < nb; k++ {
515 if iscomplex[k] == 0 {
517 ii := bi.Idamax(n, b[nb+k:], ldb)
518 remax = 1 / math.Abs(b[ii*ldb+nb+k])
519 } else if iscomplex[k] == 1 {
520 // First eigenvector of conjugate pair.
522 for ii := 0; ii < n; ii++ {
523 emax = math.Max(emax, math.Abs(b[ii*ldb+nb+k])+math.Abs(b[ii*ldb+nb+k+1]))
526 // Second eigenvector of conjugate pair
527 // will reuse this value of remax.
529 bi.Dscal(n, remax, b[nb+k:], ldb)
531 impl.Dlacpy(blas.All, n, nb-iv, b[nb+iv:], ldb, vr[ki2:], ldvr)
543 if side == lapack.RightEV {
548 // Compute left eigenvectors.
550 // For complex left vector, iv is for real part and iv+1 for complex
551 // part. Non-blocked version always uses iv=0. Blocked version starts
552 // with iv=0, goes up to nb-2 or nb-1.
556 for ki := 0; ki < n; ki++ {
558 // Previous iteration ki-1 was first of conjugate pair,
559 // so this ki is second of conjugate pair.
564 if ki == n-1 || t[(ki+1)*ldt+ki] == 0 {
565 // Last column or zero on sub-diagonal, so this ki must
566 // be real eigenvalue.
569 // Non-zero on sub-diagonal, so this ki is first of
573 if howmny == lapack.SelectedEV && !selected[ki] {
577 // Compute the ki-th eigenvalue (wr,wi).
581 wi = math.Sqrt(math.Abs(t[ki*ldt+ki+1])) * math.Sqrt(math.Abs(t[(ki+1)*ldt+ki]))
583 smin := math.Max(ulp*(math.Abs(wr)+math.Abs(wi)), smlnum)
586 // Real left eigenvector.
589 // Form right-hand side.
590 for k := ki + 1; k < n; k++ {
591 b[k*ldb+iv] = -t[ki*ldt+k]
593 // Solve transposed quasi-triangular system:
594 // [ T[ki+1:n,ki+1:n] - wr ]^T * X = scale*b
597 for j := ki + 1; j < n; {
598 if j == n-1 || t[(j+1)*ldt+j] == 0 {
599 // 1×1 diagonal block.
601 // Scale if necessary to avoid overflow
602 // when forming the right-hand side.
603 if norms[j] > vcrit {
605 bi.Dscal(n-ki, rec, b[ki*ldb+iv:], ldb)
609 b[j*ldb+iv] -= bi.Ddot(j-ki-1, t[(ki+1)*ldt+j:], ldt, b[(ki+1)*ldb+iv:], ldb)
610 // Solve [ T[j,j] - wr ]^T * X = b.
611 scale, _, _ := impl.Dlaln2(false, 1, 1, smin, 1, t[j*ldt+j:], ldt,
612 1, 1, b[j*ldb+iv:], ldb, wr, 0, x[:1], 2)
613 // Scale if necessary.
615 bi.Dscal(n-ki, scale, b[ki*ldb+iv:], ldb)
618 vmax = math.Max(math.Abs(b[j*ldb+iv]), vmax)
619 vcrit = bignum / vmax
622 // 2×2 diagonal block.
624 // Scale if necessary to avoid overflow
625 // when forming the right-hand side.
626 beta := math.Max(norms[j], norms[j+1])
628 bi.Dscal(n-ki+1, 1/vmax, b[ki*ldb+iv:], 1)
632 b[j*ldb+iv] -= bi.Ddot(j-ki-1, t[(ki+1)*ldt+j:], ldt, b[(ki+1)*ldb+iv:], ldb)
633 b[(j+1)*ldb+iv] -= bi.Ddot(j-ki-1, t[(ki+1)*ldt+j+1:], ldt, b[(ki+1)*ldb+iv:], ldb)
635 // [ T[j,j]-wr T[j,j+1] ]^T * X = scale*[ b1 ]
636 // [ T[j+1,j] T[j+1,j+1]-wr ] [ b2 ]
637 scale, _, _ := impl.Dlaln2(true, 2, 1, smin, 1, t[j*ldt+j:], ldt,
638 1, 1, b[j*ldb+iv:], ldb, wr, 0, x[:3], 2)
639 // Scale if necessary.
641 bi.Dscal(n-ki, scale, b[ki*ldb+iv:], ldb)
644 b[(j+1)*ldb+iv] = x[2]
645 vmax = math.Max(vmax, math.Max(math.Abs(b[j*ldb+iv]), math.Abs(b[(j+1)*ldb+iv])))
646 vcrit = bignum / vmax
650 // Copy the vector x or Q*x to VL and normalize.
652 case howmny != lapack.AllEVMulQ:
653 // No back-transform: copy x to VL and normalize.
654 bi.Dcopy(n-ki, b[ki*ldb+iv:], ldb, vl[ki*ldvl+is:], ldvl)
655 ii := bi.Idamax(n-ki, vl[ki*ldvl+is:], ldvl) + ki
656 remax := 1 / math.Abs(vl[ii*ldvl+is])
657 bi.Dscal(n-ki, remax, vl[ki*ldvl+is:], ldvl)
658 for k := 0; k < ki; k++ {
662 // Version 1: back-transform each vector with Gemv, Q*x.
664 bi.Dgemv(blas.NoTrans, n, n-ki-1,
665 1, vl[ki+1:], ldvl, b[(ki+1)*ldb+iv:], ldb,
666 b[ki*ldb+iv], vl[ki:], ldvl)
668 ii := bi.Idamax(n, vl[ki:], ldvl)
669 remax := 1 / math.Abs(vl[ii*ldvl+ki])
670 bi.Dscal(n, remax, vl[ki:], ldvl)
672 // Version 2: back-transform block of vectors with Gemm
673 // zero out above vector.
674 for k := 0; k < ki; k++ {
678 // Back-transform and normalization is done below.
681 // Complex left eigenvector.
684 // [ [ T[ki,ki] T[ki,ki+1] ]^T - (wr - i* wi) ]*X = 0.
685 // [ [ T[ki+1,ki] T[ki+1,ki+1] ] ]
686 if math.Abs(t[ki*ldt+ki+1]) >= math.Abs(t[(ki+1)*ldt+ki]) {
687 b[ki*ldb+iv] = wi / t[ki*ldt+ki+1]
688 b[(ki+1)*ldb+iv+1] = 1
691 b[(ki+1)*ldb+iv+1] = -wi / t[(ki+1)*ldt+ki]
695 // Form right-hand side.
696 for k := ki + 2; k < n; k++ {
697 b[k*ldb+iv] = -b[ki*ldb+iv] * t[ki*ldt+k]
698 b[k*ldb+iv+1] = -b[(ki+1)*ldb+iv+1] * t[(ki+1)*ldt+k]
700 // Solve transposed quasi-triangular system:
701 // [ T[ki+2:n,ki+2:n]^T - (wr-i*wi) ]*X = b1+i*b2
704 for j := ki + 2; j < n; {
705 if j == n-1 || t[(j+1)*ldt+j] == 0 {
706 // 1×1 diagonal block.
708 // Scale if necessary to avoid overflow
709 // when forming the right-hand side elements.
710 if norms[j] > vcrit {
712 bi.Dscal(n-ki, rec, b[ki*ldb+iv:], ldb)
713 bi.Dscal(n-ki, rec, b[ki*ldb+iv+1:], ldb)
717 b[j*ldb+iv] -= bi.Ddot(j-ki-2, t[(ki+2)*ldt+j:], ldt, b[(ki+2)*ldb+iv:], ldb)
718 b[j*ldb+iv+1] -= bi.Ddot(j-ki-2, t[(ki+2)*ldt+j:], ldt, b[(ki+2)*ldb+iv+1:], ldb)
719 // Solve [ T[j,j]-(wr-i*wi) ]*(X11+i*X12) = b1+i*b2.
720 scale, _, _ := impl.Dlaln2(false, 1, 2, smin, 1, t[j*ldt+j:], ldt,
721 1, 1, b[j*ldb+iv:], ldb, wr, -wi, x[:2], 2)
722 // Scale if necessary.
724 bi.Dscal(n-ki, scale, b[ki*ldb+iv:], ldb)
725 bi.Dscal(n-ki, scale, b[ki*ldb+iv+1:], ldb)
729 vmax = math.Max(vmax, math.Max(math.Abs(b[j*ldb+iv]), math.Abs(b[j*ldb+iv+1])))
730 vcrit = bignum / vmax
733 // 2×2 diagonal block.
735 // Scale if necessary to avoid overflow
736 // when forming the right-hand side elements.
737 if math.Max(norms[j], norms[j+1]) > vcrit {
739 bi.Dscal(n-ki, rec, b[ki*ldb+iv:], ldb)
740 bi.Dscal(n-ki, rec, b[ki*ldb+iv+1:], ldb)
744 b[j*ldb+iv] -= bi.Ddot(j-ki-2, t[(ki+2)*ldt+j:], ldt, b[(ki+2)*ldb+iv:], ldb)
745 b[j*ldb+iv+1] -= bi.Ddot(j-ki-2, t[(ki+2)*ldt+j:], ldt, b[(ki+2)*ldb+iv+1:], ldb)
746 b[(j+1)*ldb+iv] -= bi.Ddot(j-ki-2, t[(ki+2)*ldt+j+1:], ldt, b[(ki+2)*ldb+iv:], ldb)
747 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)
748 // Solve 2×2 complex linear equation
749 // [ [T[j,j] T[j,j+1] ]^T - (wr-i*wi)*I ]*X = scale*b
750 // [ [T[j+1,j] T[j+1,j+1]] ]
751 scale, _, _ := impl.Dlaln2(true, 2, 2, smin, 1, t[j*ldt+j:], ldt,
752 1, 1, b[j*ldb+iv:], ldb, wr, -wi, x[:], 2)
753 // Scale if necessary.
755 bi.Dscal(n-ki, scale, b[ki*ldb+iv:], ldb)
756 bi.Dscal(n-ki, scale, b[ki*ldb+iv+1:], ldb)
760 b[(j+1)*ldb+iv] = x[2]
761 b[(j+1)*ldb+iv+1] = x[3]
762 vmax01 := math.Max(math.Abs(x[0]), math.Abs(x[1]))
763 vmax23 := math.Max(math.Abs(x[2]), math.Abs(x[3]))
764 vmax = math.Max(vmax, math.Max(vmax01, vmax23))
765 vcrit = bignum / vmax
769 // Copy the vector x or Q*x to VL and normalize.
771 case howmny != lapack.AllEVMulQ:
772 // No back-transform: copy x to VL and normalize.
773 bi.Dcopy(n-ki, b[ki*ldb+iv:], ldb, vl[ki*ldvl+is:], ldvl)
774 bi.Dcopy(n-ki, b[ki*ldb+iv+1:], ldb, vl[ki*ldvl+is+1:], ldvl)
776 for k := ki; k < n; k++ {
777 emax = math.Max(emax, math.Abs(vl[k*ldvl+is])+math.Abs(vl[k*ldvl+is+1]))
780 bi.Dscal(n-ki, remax, vl[ki*ldvl+is:], ldvl)
781 bi.Dscal(n-ki, remax, vl[ki*ldvl+is+1:], ldvl)
782 for k := 0; k < ki; k++ {
787 // Version 1: back-transform each vector with GEMV, Q*x.
789 bi.Dgemv(blas.NoTrans, n, n-ki-2,
790 1, vl[ki+2:], ldvl, b[(ki+2)*ldb+iv:], ldb,
791 b[ki*ldb+iv], vl[ki:], ldvl)
792 bi.Dgemv(blas.NoTrans, n, n-ki-2,
793 1, vl[ki+2:], ldvl, b[(ki+2)*ldb+iv+1:], ldb,
794 b[(ki+1)*ldb+iv+1], vl[ki+1:], ldvl)
796 bi.Dscal(n, b[ki*ldb+iv], vl[ki:], ldvl)
797 bi.Dscal(n, b[(ki+1)*ldb+iv+1], vl[ki+1:], ldvl)
800 for k := 0; k < n; k++ {
801 emax = math.Max(emax, math.Abs(vl[k*ldvl+ki])+math.Abs(vl[k*ldvl+ki+1]))
804 bi.Dscal(n, remax, vl[ki:], ldvl)
805 bi.Dscal(n, remax, vl[ki+1:], ldvl)
807 // Version 2: back-transform block of vectors with GEMM.
808 // Zero out above vector.
809 // Could go from ki-nv+1 to ki-1.
810 for k := 0; k < ki; k++ {
815 iscomplex[iv+1] = -ip
817 // Back-transform and normalization is done below.
821 // Blocked version of back-transform.
822 // For complex case, ki2 includes both vectors ki and ki+1.
827 // Columns [0:iv] of work are valid vectors. When the
828 // number of vectors stored reaches nb-1 or nb, or if
829 // this was last vector, do the Gemm.
830 if iv >= nb-2 || ki2 == n-1 {
831 bi.Dgemm(blas.NoTrans, blas.NoTrans, n, iv+1, n-ki2+iv,
832 1, vl[ki2-iv:], ldvl, b[(ki2-iv)*ldb:], ldb,
834 // Normalize vectors.
836 for k := 0; k <= iv; k++ {
837 if iscomplex[k] == 0 {
839 ii := bi.Idamax(n, b[nb+k:], ldb)
840 remax = 1 / math.Abs(b[ii*ldb+nb+k])
841 } else if iscomplex[k] == 1 {
842 // First eigenvector of conjugate pair.
844 for ii := 0; ii < n; ii++ {
845 emax = math.Max(emax, math.Abs(b[ii*ldb+nb+k])+math.Abs(b[ii*ldb+nb+k+1]))
848 // Second eigenvector of conjugate pair
849 // will reuse this value of remax.
851 bi.Dscal(n, remax, b[nb+k:], ldb)
853 impl.Dlacpy(blas.All, n, iv+1, b[nb:], ldb, vl[ki2-iv:], ldvl)