github.com/gonum/lapack@v0.0.0-20181123203213-e4cdc5a0bff9/native/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 native
     6  
     7  import (
     8  	"math"
     9  
    10  	"github.com/gonum/blas"
    11  	"github.com/gonum/blas/blas64"
    12  	"github.com/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  //  A = Q T Q^T,
    19  // as computed by Dhseqr.
    20  //
    21  // The right eigenvector x of T corresponding to an
    22  // eigenvalue λ is defined by
    23  //  T x = λ x,
    24  // and the left eigenvector is defined by
    25  //  y^H T = λ y^H,
    26  // where y^H is the conjugate transpose of y.
    27  //
    28  // The eigenvalues are read directly from the diagonal blocks of T.
    29  //
    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.
    34  //
    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.
    39  //
    40  // If howmny == lapack.AllEV, all right and/or left eigenvectors will be
    41  // computed.
    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.
    47  //
    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.
    56  //
    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.
    63  //
    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.
    69  //
    70  // On return, if side is lapack.LeftEV or lapack.RightLeftEV,
    71  // VL will contain:
    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
    77  //                                  eigenvalues.
    78  // VL is not referenced if side == lapack.RightEV.
    79  //
    80  // On return, if side is lapack.RightEV or lapack.RightLeftEV,
    81  // VR will contain:
    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
    87  //                                  eigenvalues.
    88  // VR is not referenced if side == lapack.LeftEV.
    89  //
    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.
    93  //
    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
    96  // |x| + |y|.
    97  //
    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.
   101  //
   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].
   104  //
   105  // Dtrevc3 returns the number of columns in VL and/or VR actually used to store
   106  // the eigenvectors.
   107  //
   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) {
   110  	switch side {
   111  	default:
   112  		panic(badSide)
   113  	case lapack.RightEV, lapack.LeftEV, lapack.RightLeftEV:
   114  	}
   115  	switch howmny {
   116  	default:
   117  		panic(badHowMany)
   118  	case lapack.AllEV, lapack.AllEVMulQ, lapack.SelectedEV:
   119  	}
   120  	switch {
   121  	case n < 0:
   122  		panic(nLT0)
   123  	case len(work) < lwork:
   124  		panic(shortWork)
   125  	case lwork < max(1, 3*n) && lwork != -1:
   126  		panic(badWork)
   127  	}
   128  	if lwork != -1 {
   129  		if howmny == lapack.SelectedEV {
   130  			if len(selected) != n {
   131  				panic("lapack: bad selected length")
   132  			}
   133  			// Set m to the number of columns required to store the
   134  			// selected eigenvectors, and standardize the slice
   135  			// selected.
   136  			for j := 0; j < n; {
   137  				if j == n-1 || t[(j+1)*ldt+j] == 0 {
   138  					// Diagonal 1×1 block corresponding to a
   139  					// real eigenvalue.
   140  					if selected[j] {
   141  						m++
   142  					}
   143  					j++
   144  				} else {
   145  					// Diagonal 2×2 block corresponding to a
   146  					// complex eigenvalue.
   147  					if selected[j] || selected[j+1] {
   148  						selected[j] = true
   149  						selected[j+1] = false
   150  						m += 2
   151  					}
   152  					j += 2
   153  				}
   154  			}
   155  		} else {
   156  			m = n
   157  		}
   158  		if m > mm {
   159  			panic("lapack: insufficient number of columns")
   160  		}
   161  		checkMatrix(n, n, t, ldt)
   162  		if (side == lapack.RightEV || side == lapack.RightLeftEV) && m > 0 {
   163  			checkMatrix(n, m, vr, ldvr)
   164  		}
   165  		if (side == lapack.LeftEV || side == lapack.RightLeftEV) && m > 0 {
   166  			checkMatrix(n, m, vl, ldvl)
   167  		}
   168  	}
   169  
   170  	// Quick return if possible.
   171  	if n == 0 {
   172  		work[0] = 1
   173  		return m
   174  	}
   175  
   176  	const (
   177  		nbmin = 8
   178  		nbmax = 128
   179  	)
   180  	nb := impl.Ilaenv(1, "DTREVC", string(side)+string(howmny), n, -1, -1, -1)
   181  
   182  	// Quick return in case of a workspace query.
   183  	if lwork == -1 {
   184  		work[0] = float64(n + 2*n*nb)
   185  		return m
   186  	}
   187  
   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)
   193  	} else {
   194  		nb = 1
   195  	}
   196  
   197  	// Set the constants to control overflow.
   198  	ulp := dlamchP
   199  	smlnum := float64(n) / ulp * dlamchS
   200  	bignum := (1 - ulp) / smlnum
   201  
   202  	// Split work into a vector of column norms and an n×2*nb matrix b.
   203  	norms := work[:n]
   204  	ldb := 2 * nb
   205  	b := work[n : n+n*ldb]
   206  
   207  	// Compute 1-norm of each column of strictly upper triangular part of T
   208  	// to control overflow in triangular solver.
   209  	norms[0] = 0
   210  	for j := 1; j < n; j++ {
   211  		var cn float64
   212  		for i := 0; i < j; i++ {
   213  			cn += math.Abs(t[i*ldt+j])
   214  		}
   215  		norms[j] = cn
   216  	}
   217  
   218  	bi := blas64.Implementation()
   219  
   220  	var (
   221  		x [4]float64
   222  
   223  		iv int // Index of column in current block.
   224  		is int
   225  
   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).
   230  		ip        int
   231  		iscomplex [nbmax]int // Stores ip for each column in current block.
   232  	)
   233  
   234  	if side == lapack.LeftEV {
   235  		goto leftev
   236  	}
   237  
   238  	// Compute right eigenvectors.
   239  
   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.
   243  	iv = max(2, nb) - 1
   244  	ip = 0
   245  	is = m - 1
   246  	for ki := n - 1; ki >= 0; ki-- {
   247  		if ip == -1 {
   248  			// Previous iteration (ki+1) was second of
   249  			// conjugate pair, so this ki is first of
   250  			// conjugate pair.
   251  			ip = 1
   252  			continue
   253  		}
   254  
   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.
   258  			ip = 0
   259  		} else {
   260  			// Non-zero on sub-diagonal, so this ki is
   261  			// second of conjugate pair.
   262  			ip = -1
   263  		}
   264  
   265  		if howmny == lapack.SelectedEV {
   266  			if ip == 0 {
   267  				if !selected[ki] {
   268  					continue
   269  				}
   270  			} else if !selected[ki-1] {
   271  				continue
   272  			}
   273  		}
   274  
   275  		// Compute the ki-th eigenvalue (wr,wi).
   276  		wr := t[ki*ldt+ki]
   277  		var wi float64
   278  		if ip != 0 {
   279  			wi = math.Sqrt(math.Abs(t[ki*ldt+ki-1])) * math.Sqrt(math.Abs(t[(ki-1)*ldt+ki]))
   280  		}
   281  		smin := math.Max(ulp*(math.Abs(wr)+math.Abs(wi)), smlnum)
   282  
   283  		if ip == 0 {
   284  			// Real right eigenvector.
   285  
   286  			b[ki*ldb+iv] = 1
   287  			// Form right-hand side.
   288  			for k := 0; k < ki; k++ {
   289  				b[k*ldb+iv] = -t[k*ldt+ki]
   290  			}
   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
   299  					// right-hand side.
   300  					if xnorm > 1 && norms[j] > bignum/xnorm {
   301  						x[0] /= xnorm
   302  						scale /= xnorm
   303  					}
   304  					// Scale if necessary.
   305  					if scale != 1 {
   306  						bi.Dscal(ki+1, scale, b[iv:], ldb)
   307  					}
   308  					b[j*ldb+iv] = x[0]
   309  					// Update right-hand side.
   310  					bi.Daxpy(j, -x[0], t[j:], ldt, b[iv:], ldb)
   311  					j--
   312  				} else {
   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.
   318  					if xnorm > 1 {
   319  						beta := math.Max(norms[j-1], norms[j])
   320  						if beta > bignum/xnorm {
   321  							x[0] /= xnorm
   322  							x[2] /= xnorm
   323  							scale /= xnorm
   324  						}
   325  					}
   326  					// Scale if necessary.
   327  					if scale != 1 {
   328  						bi.Dscal(ki+1, scale, b[iv:], ldb)
   329  					}
   330  					b[(j-1)*ldb+iv] = x[0]
   331  					b[j*ldb+iv] = x[2]
   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)
   335  					j -= 2
   336  				}
   337  			}
   338  			// Copy the vector x or Q*x to VR and normalize.
   339  			switch {
   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++ {
   347  					vr[k*ldvr+is] = 0
   348  				}
   349  			case nb == 1:
   350  				// Version 1: back-transform each vector with GEMV, Q*x.
   351  				if ki > 0 {
   352  					bi.Dgemv(blas.NoTrans, n, ki, 1, vr, ldvr, b[iv:], ldb,
   353  						b[ki*ldb+iv], vr[ki:], ldvr)
   354  				}
   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)
   358  			default:
   359  				// Version 2: back-transform block of vectors with GEMM.
   360  				// Zero out below vector.
   361  				for k := ki + 1; k < n; k++ {
   362  					b[k*ldb+iv] = 0
   363  				}
   364  				iscomplex[iv] = ip
   365  				// Back-transform and normalization is done below.
   366  			}
   367  		} else {
   368  			// Complex right eigenvector.
   369  
   370  			// Initial solve
   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]
   376  			} else {
   377  				b[(ki-1)*ldb+iv-1] = -wi / t[ki*ldt+ki-1]
   378  				b[ki*ldb+iv] = 1
   379  			}
   380  			b[ki*ldb+iv-1] = 0
   381  			b[(ki-1)*ldb+iv] = 0
   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]
   386  			}
   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.
   392  
   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 {
   398  						x[0] /= xnorm
   399  						x[1] /= xnorm
   400  						scale /= xnorm
   401  					}
   402  					// Scale if necessary.
   403  					if scale != 1 {
   404  						bi.Dscal(ki+1, scale, b[iv-1:], ldb)
   405  						bi.Dscal(ki+1, scale, b[iv:], ldb)
   406  					}
   407  					b[j*ldb+iv-1] = x[0]
   408  					b[j*ldb+iv] = x[1]
   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)
   412  					j--
   413  				} else {
   414  					// 2×2 diagonal block.
   415  
   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.
   420  					if xnorm > 1 {
   421  						beta := math.Max(norms[j-1], norms[j])
   422  						if beta > bignum/xnorm {
   423  							rec := 1 / xnorm
   424  							x[0] *= rec
   425  							x[1] *= rec
   426  							x[2] *= rec
   427  							x[3] *= rec
   428  							scale *= rec
   429  						}
   430  					}
   431  					// Scale if necessary.
   432  					if scale != 1 {
   433  						bi.Dscal(ki+1, scale, b[iv-1:], ldb)
   434  						bi.Dscal(ki+1, scale, b[iv:], ldb)
   435  					}
   436  					b[(j-1)*ldb+iv-1] = x[0]
   437  					b[(j-1)*ldb+iv] = x[1]
   438  					b[j*ldb+iv-1] = x[2]
   439  					b[j*ldb+iv] = x[3]
   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)
   445  					j -= 2
   446  				}
   447  			}
   448  
   449  			// Copy the vector x or Q*x to VR and normalize.
   450  			switch {
   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)
   455  				emax := 0.0
   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]))
   458  				}
   459  				remax := 1 / emax
   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++ {
   463  					vr[k*ldvr+is-1] = 0
   464  					vr[k*ldvr+is] = 0
   465  				}
   466  			case nb == 1:
   467  				// Version 1: back-transform each vector with GEMV, Q*x.
   468  				if ki-1 > 0 {
   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)
   473  				} else {
   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)
   476  				}
   477  				emax := 0.0
   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]))
   480  				}
   481  				remax := 1 / emax
   482  				bi.Dscal(n, remax, vr[ki-1:], ldvr)
   483  				bi.Dscal(n, remax, vr[ki:], ldvr)
   484  			default:
   485  				// Version 2: back-transform block of vectors with GEMM.
   486  				// Zero out below vector.
   487  				for k := ki + 1; k < n; k++ {
   488  					b[k*ldb+iv-1] = 0
   489  					b[k*ldb+iv] = 0
   490  				}
   491  				iscomplex[iv-1] = -ip
   492  				iscomplex[iv] = ip
   493  				iv--
   494  				// Back-transform and normalization is done below.
   495  			}
   496  		}
   497  		if nb > 1 {
   498  			// Blocked version of back-transform.
   499  
   500  			// For complex case, ki2 includes both vectors (ki-1 and ki).
   501  			ki2 := ki
   502  			if ip != 0 {
   503  				ki2--
   504  			}
   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,
   511  					0, b[nb+iv:], ldb)
   512  				// Normalize vectors.
   513  				var remax float64
   514  				for k := iv; k < nb; k++ {
   515  					if iscomplex[k] == 0 {
   516  						// Real eigenvector.
   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.
   521  						emax := 0.0
   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]))
   524  						}
   525  						remax = 1 / emax
   526  						// Second eigenvector of conjugate pair
   527  						// will reuse this value of remax.
   528  					}
   529  					bi.Dscal(n, remax, b[nb+k:], ldb)
   530  				}
   531  				impl.Dlacpy(blas.All, n, nb-iv, b[nb+iv:], ldb, vr[ki2:], ldvr)
   532  				iv = nb - 1
   533  			} else {
   534  				iv--
   535  			}
   536  		}
   537  		is--
   538  		if ip != 0 {
   539  			is--
   540  		}
   541  	}
   542  
   543  	if side == lapack.RightEV {
   544  		return m
   545  	}
   546  
   547  leftev:
   548  	// Compute left eigenvectors.
   549  
   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.
   553  	iv = 0
   554  	ip = 0
   555  	is = 0
   556  	for ki := 0; ki < n; ki++ {
   557  		if ip == 1 {
   558  			// Previous iteration ki-1 was first of conjugate pair,
   559  			// so this ki is second of conjugate pair.
   560  			ip = -1
   561  			continue
   562  		}
   563  
   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.
   567  			ip = 0
   568  		} else {
   569  			// Non-zero on sub-diagonal, so this ki is first of
   570  			// conjugate pair.
   571  			ip = 1
   572  		}
   573  		if howmny == lapack.SelectedEV && !selected[ki] {
   574  			continue
   575  		}
   576  
   577  		// Compute the ki-th eigenvalue (wr,wi).
   578  		wr := t[ki*ldt+ki]
   579  		var wi float64
   580  		if ip != 0 {
   581  			wi = math.Sqrt(math.Abs(t[ki*ldt+ki+1])) * math.Sqrt(math.Abs(t[(ki+1)*ldt+ki]))
   582  		}
   583  		smin := math.Max(ulp*(math.Abs(wr)+math.Abs(wi)), smlnum)
   584  
   585  		if ip == 0 {
   586  			// Real left eigenvector.
   587  
   588  			b[ki*ldb+iv] = 1
   589  			// Form right-hand side.
   590  			for k := ki + 1; k < n; k++ {
   591  				b[k*ldb+iv] = -t[ki*ldt+k]
   592  			}
   593  			// Solve transposed quasi-triangular system:
   594  			//  [ T[ki+1:n,ki+1:n] - wr ]^T * X = scale*b
   595  			vmax := 1.0
   596  			vcrit := bignum
   597  			for j := ki + 1; j < n; {
   598  				if j == n-1 || t[(j+1)*ldt+j] == 0 {
   599  					// 1×1 diagonal block.
   600  
   601  					// Scale if necessary to avoid overflow
   602  					// when forming the right-hand side.
   603  					if norms[j] > vcrit {
   604  						rec := 1 / vmax
   605  						bi.Dscal(n-ki, rec, b[ki*ldb+iv:], ldb)
   606  						vmax = 1
   607  						vcrit = bignum
   608  					}
   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.
   614  					if scale != 1 {
   615  						bi.Dscal(n-ki, scale, b[ki*ldb+iv:], ldb)
   616  					}
   617  					b[j*ldb+iv] = x[0]
   618  					vmax = math.Max(math.Abs(b[j*ldb+iv]), vmax)
   619  					vcrit = bignum / vmax
   620  					j++
   621  				} else {
   622  					// 2×2 diagonal block.
   623  
   624  					// Scale if necessary to avoid overflow
   625  					// when forming the right-hand side.
   626  					beta := math.Max(norms[j], norms[j+1])
   627  					if beta > vcrit {
   628  						bi.Dscal(n-ki+1, 1/vmax, b[ki*ldb+iv:], 1)
   629  						vmax = 1
   630  						vcrit = bignum
   631  					}
   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)
   634  					// Solve
   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.
   640  					if scale != 1 {
   641  						bi.Dscal(n-ki, scale, b[ki*ldb+iv:], ldb)
   642  					}
   643  					b[j*ldb+iv] = x[0]
   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
   647  					j += 2
   648  				}
   649  			}
   650  			// Copy the vector x or Q*x to VL and normalize.
   651  			switch {
   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++ {
   659  					vl[k*ldvl+is] = 0
   660  				}
   661  			case nb == 1:
   662  				// Version 1: back-transform each vector with Gemv, Q*x.
   663  				if n-ki-1 > 0 {
   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)
   667  				}
   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)
   671  			default:
   672  				// Version 2: back-transform block of vectors with Gemm
   673  				// zero out above vector.
   674  				for k := 0; k < ki; k++ {
   675  					b[k*ldb+iv] = 0
   676  				}
   677  				iscomplex[iv] = ip
   678  				// Back-transform and normalization is done below.
   679  			}
   680  		} else {
   681  			// Complex left eigenvector.
   682  
   683  			// Initial solve:
   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
   689  			} else {
   690  				b[ki*ldb+iv] = 1
   691  				b[(ki+1)*ldb+iv+1] = -wi / t[(ki+1)*ldt+ki]
   692  			}
   693  			b[(ki+1)*ldb+iv] = 0
   694  			b[ki*ldb+iv+1] = 0
   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]
   699  			}
   700  			// Solve transposed quasi-triangular system:
   701  			// [ T[ki+2:n,ki+2:n]^T - (wr-i*wi) ]*X = b1+i*b2
   702  			vmax := 1.0
   703  			vcrit := bignum
   704  			for j := ki + 2; j < n; {
   705  				if j == n-1 || t[(j+1)*ldt+j] == 0 {
   706  					// 1×1 diagonal block.
   707  
   708  					// Scale if necessary to avoid overflow
   709  					// when forming the right-hand side elements.
   710  					if norms[j] > vcrit {
   711  						rec := 1 / vmax
   712  						bi.Dscal(n-ki, rec, b[ki*ldb+iv:], ldb)
   713  						bi.Dscal(n-ki, rec, b[ki*ldb+iv+1:], ldb)
   714  						vmax = 1
   715  						vcrit = bignum
   716  					}
   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.
   723  					if scale != 1 {
   724  						bi.Dscal(n-ki, scale, b[ki*ldb+iv:], ldb)
   725  						bi.Dscal(n-ki, scale, b[ki*ldb+iv+1:], ldb)
   726  					}
   727  					b[j*ldb+iv] = x[0]
   728  					b[j*ldb+iv+1] = x[1]
   729  					vmax = math.Max(vmax, math.Max(math.Abs(b[j*ldb+iv]), math.Abs(b[j*ldb+iv+1])))
   730  					vcrit = bignum / vmax
   731  					j++
   732  				} else {
   733  					// 2×2 diagonal block.
   734  
   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 {
   738  						rec := 1 / vmax
   739  						bi.Dscal(n-ki, rec, b[ki*ldb+iv:], ldb)
   740  						bi.Dscal(n-ki, rec, b[ki*ldb+iv+1:], ldb)
   741  						vmax = 1
   742  						vcrit = bignum
   743  					}
   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.
   754  					if scale != 1 {
   755  						bi.Dscal(n-ki, scale, b[ki*ldb+iv:], ldb)
   756  						bi.Dscal(n-ki, scale, b[ki*ldb+iv+1:], ldb)
   757  					}
   758  					b[j*ldb+iv] = x[0]
   759  					b[j*ldb+iv+1] = x[1]
   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
   766  					j += 2
   767  				}
   768  			}
   769  			// Copy the vector x or Q*x to VL and normalize.
   770  			switch {
   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)
   775  				emax := 0.0
   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]))
   778  				}
   779  				remax := 1 / emax
   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++ {
   783  					vl[k*ldvl+is] = 0
   784  					vl[k*ldvl+is+1] = 0
   785  				}
   786  			case nb == 1:
   787  				// Version 1: back-transform each vector with GEMV, Q*x.
   788  				if n-ki-2 > 0 {
   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)
   795  				} else {
   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)
   798  				}
   799  				emax := 0.0
   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]))
   802  				}
   803  				remax := 1 / emax
   804  				bi.Dscal(n, remax, vl[ki:], ldvl)
   805  				bi.Dscal(n, remax, vl[ki+1:], ldvl)
   806  			default:
   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++ {
   811  					b[k*ldb+iv] = 0
   812  					b[k*ldb+iv+1] = 0
   813  				}
   814  				iscomplex[iv] = ip
   815  				iscomplex[iv+1] = -ip
   816  				iv++
   817  				// Back-transform and normalization is done below.
   818  			}
   819  		}
   820  		if nb > 1 {
   821  			// Blocked version of back-transform.
   822  			// For complex case, ki2 includes both vectors ki and ki+1.
   823  			ki2 := ki
   824  			if ip != 0 {
   825  				ki2++
   826  			}
   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,
   833  					0, b[nb:], ldb)
   834  				// Normalize vectors.
   835  				var remax float64
   836  				for k := 0; k <= iv; k++ {
   837  					if iscomplex[k] == 0 {
   838  						// Real eigenvector.
   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.
   843  						emax := 0.0
   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]))
   846  						}
   847  						remax = 1 / emax
   848  						// Second eigenvector of conjugate pair
   849  						// will reuse this value of remax.
   850  					}
   851  					bi.Dscal(n, remax, b[nb+k:], ldb)
   852  				}
   853  				impl.Dlacpy(blas.All, n, iv+1, b[nb:], ldb, vl[ki2-iv:], ldvl)
   854  				iv = 0
   855  			} else {
   856  				iv++
   857  			}
   858  		}
   859  		is++
   860  		if ip != 0 {
   861  			is++
   862  		}
   863  	}
   864  
   865  	return m
   866  }