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  }