github.com/gonum/lapack@v0.0.0-20181123203213-e4cdc5a0bff9/testlapack/dgeev.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 testlapack
     6  
     7  import (
     8  	"fmt"
     9  	"math"
    10  	"math/cmplx"
    11  	"math/rand"
    12  	"strconv"
    13  	"testing"
    14  
    15  	"github.com/gonum/blas"
    16  	"github.com/gonum/blas/blas64"
    17  	"github.com/gonum/floats"
    18  	"github.com/gonum/lapack"
    19  )
    20  
    21  type Dgeever interface {
    22  	Dgeev(jobvl lapack.LeftEVJob, jobvr lapack.RightEVJob, n int, a []float64, lda int,
    23  		wr, wi []float64, vl []float64, ldvl int, vr []float64, ldvr int, work []float64, lwork int) int
    24  }
    25  
    26  type dgeevTest struct {
    27  	a      blas64.General
    28  	evWant []complex128 // If nil, the eigenvalues are not known.
    29  	valTol float64      // Tolerance for eigenvalue checks.
    30  	vecTol float64      // Tolerance for eigenvector checks.
    31  }
    32  
    33  func DgeevTest(t *testing.T, impl Dgeever) {
    34  	rnd := rand.New(rand.NewSource(1))
    35  
    36  	for i, test := range []dgeevTest{
    37  		{
    38  			a:      A123{}.Matrix(),
    39  			evWant: A123{}.Eigenvalues(),
    40  		},
    41  
    42  		dgeevTestForAntisymRandom(10, rnd),
    43  		dgeevTestForAntisymRandom(11, rnd),
    44  		dgeevTestForAntisymRandom(50, rnd),
    45  		dgeevTestForAntisymRandom(51, rnd),
    46  		dgeevTestForAntisymRandom(100, rnd),
    47  		dgeevTestForAntisymRandom(101, rnd),
    48  
    49  		{
    50  			a:      Circulant(2).Matrix(),
    51  			evWant: Circulant(2).Eigenvalues(),
    52  		},
    53  		{
    54  			a:      Circulant(3).Matrix(),
    55  			evWant: Circulant(3).Eigenvalues(),
    56  		},
    57  		{
    58  			a:      Circulant(4).Matrix(),
    59  			evWant: Circulant(4).Eigenvalues(),
    60  		},
    61  		{
    62  			a:      Circulant(5).Matrix(),
    63  			evWant: Circulant(5).Eigenvalues(),
    64  		},
    65  		{
    66  			a:      Circulant(10).Matrix(),
    67  			evWant: Circulant(10).Eigenvalues(),
    68  		},
    69  		{
    70  			a:      Circulant(15).Matrix(),
    71  			evWant: Circulant(15).Eigenvalues(),
    72  			valTol: 1e-12,
    73  		},
    74  		{
    75  			a:      Circulant(30).Matrix(),
    76  			evWant: Circulant(30).Eigenvalues(),
    77  			valTol: 1e-11,
    78  			vecTol: 1e-12,
    79  		},
    80  		{
    81  			a:      Circulant(50).Matrix(),
    82  			evWant: Circulant(50).Eigenvalues(),
    83  			valTol: 1e-11,
    84  			vecTol: 1e-12,
    85  		},
    86  		{
    87  			a:      Circulant(101).Matrix(),
    88  			evWant: Circulant(101).Eigenvalues(),
    89  			valTol: 1e-10,
    90  			vecTol: 1e-11,
    91  		},
    92  		{
    93  			a:      Circulant(150).Matrix(),
    94  			evWant: Circulant(150).Eigenvalues(),
    95  			valTol: 1e-9,
    96  			vecTol: 1e-10,
    97  		},
    98  
    99  		{
   100  			a:      Clement(2).Matrix(),
   101  			evWant: Clement(2).Eigenvalues(),
   102  		},
   103  		{
   104  			a:      Clement(3).Matrix(),
   105  			evWant: Clement(3).Eigenvalues(),
   106  		},
   107  		{
   108  			a:      Clement(4).Matrix(),
   109  			evWant: Clement(4).Eigenvalues(),
   110  		},
   111  		{
   112  			a:      Clement(5).Matrix(),
   113  			evWant: Clement(5).Eigenvalues(),
   114  		},
   115  		{
   116  			a:      Clement(10).Matrix(),
   117  			evWant: Clement(10).Eigenvalues(),
   118  		},
   119  		{
   120  			a:      Clement(15).Matrix(),
   121  			evWant: Clement(15).Eigenvalues(),
   122  		},
   123  		{
   124  			a:      Clement(30).Matrix(),
   125  			evWant: Clement(30).Eigenvalues(),
   126  			valTol: 1e-11,
   127  		},
   128  		{
   129  			a:      Clement(50).Matrix(),
   130  			evWant: Clement(50).Eigenvalues(),
   131  			valTol: 1e-7,
   132  			vecTol: 1e-11,
   133  		},
   134  
   135  		{
   136  			a:      Creation(2).Matrix(),
   137  			evWant: Creation(2).Eigenvalues(),
   138  		},
   139  		{
   140  			a:      Creation(3).Matrix(),
   141  			evWant: Creation(3).Eigenvalues(),
   142  		},
   143  		{
   144  			a:      Creation(4).Matrix(),
   145  			evWant: Creation(4).Eigenvalues(),
   146  		},
   147  		{
   148  			a:      Creation(5).Matrix(),
   149  			evWant: Creation(5).Eigenvalues(),
   150  		},
   151  		{
   152  			a:      Creation(10).Matrix(),
   153  			evWant: Creation(10).Eigenvalues(),
   154  		},
   155  		{
   156  			a:      Creation(15).Matrix(),
   157  			evWant: Creation(15).Eigenvalues(),
   158  		},
   159  		{
   160  			a:      Creation(30).Matrix(),
   161  			evWant: Creation(30).Eigenvalues(),
   162  		},
   163  		{
   164  			a:      Creation(50).Matrix(),
   165  			evWant: Creation(50).Eigenvalues(),
   166  		},
   167  		{
   168  			a:      Creation(101).Matrix(),
   169  			evWant: Creation(101).Eigenvalues(),
   170  		},
   171  		{
   172  			a:      Creation(150).Matrix(),
   173  			evWant: Creation(150).Eigenvalues(),
   174  		},
   175  
   176  		{
   177  			a:      Diagonal(0).Matrix(),
   178  			evWant: Diagonal(0).Eigenvalues(),
   179  		},
   180  		{
   181  			a:      Diagonal(10).Matrix(),
   182  			evWant: Diagonal(10).Eigenvalues(),
   183  		},
   184  		{
   185  			a:      Diagonal(50).Matrix(),
   186  			evWant: Diagonal(50).Eigenvalues(),
   187  		},
   188  		{
   189  			a:      Diagonal(151).Matrix(),
   190  			evWant: Diagonal(151).Eigenvalues(),
   191  		},
   192  
   193  		{
   194  			a:      Downshift(2).Matrix(),
   195  			evWant: Downshift(2).Eigenvalues(),
   196  		},
   197  		{
   198  			a:      Downshift(3).Matrix(),
   199  			evWant: Downshift(3).Eigenvalues(),
   200  		},
   201  		{
   202  			a:      Downshift(4).Matrix(),
   203  			evWant: Downshift(4).Eigenvalues(),
   204  		},
   205  		{
   206  			a:      Downshift(5).Matrix(),
   207  			evWant: Downshift(5).Eigenvalues(),
   208  		},
   209  		{
   210  			a:      Downshift(10).Matrix(),
   211  			evWant: Downshift(10).Eigenvalues(),
   212  		},
   213  		{
   214  			a:      Downshift(15).Matrix(),
   215  			evWant: Downshift(15).Eigenvalues(),
   216  		},
   217  		{
   218  			a:      Downshift(30).Matrix(),
   219  			evWant: Downshift(30).Eigenvalues(),
   220  		},
   221  		{
   222  			a:      Downshift(50).Matrix(),
   223  			evWant: Downshift(50).Eigenvalues(),
   224  		},
   225  		{
   226  			a:      Downshift(101).Matrix(),
   227  			evWant: Downshift(101).Eigenvalues(),
   228  		},
   229  		{
   230  			a:      Downshift(150).Matrix(),
   231  			evWant: Downshift(150).Eigenvalues(),
   232  		},
   233  
   234  		{
   235  			a:      Fibonacci(2).Matrix(),
   236  			evWant: Fibonacci(2).Eigenvalues(),
   237  		},
   238  		{
   239  			a:      Fibonacci(3).Matrix(),
   240  			evWant: Fibonacci(3).Eigenvalues(),
   241  		},
   242  		{
   243  			a:      Fibonacci(4).Matrix(),
   244  			evWant: Fibonacci(4).Eigenvalues(),
   245  		},
   246  		{
   247  			a:      Fibonacci(5).Matrix(),
   248  			evWant: Fibonacci(5).Eigenvalues(),
   249  		},
   250  		{
   251  			a:      Fibonacci(10).Matrix(),
   252  			evWant: Fibonacci(10).Eigenvalues(),
   253  		},
   254  		{
   255  			a:      Fibonacci(15).Matrix(),
   256  			evWant: Fibonacci(15).Eigenvalues(),
   257  		},
   258  		{
   259  			a:      Fibonacci(30).Matrix(),
   260  			evWant: Fibonacci(30).Eigenvalues(),
   261  		},
   262  		{
   263  			a:      Fibonacci(50).Matrix(),
   264  			evWant: Fibonacci(50).Eigenvalues(),
   265  		},
   266  		{
   267  			a:      Fibonacci(101).Matrix(),
   268  			evWant: Fibonacci(101).Eigenvalues(),
   269  		},
   270  		{
   271  			a:      Fibonacci(150).Matrix(),
   272  			evWant: Fibonacci(150).Eigenvalues(),
   273  		},
   274  
   275  		{
   276  			a:      Gear(2).Matrix(),
   277  			evWant: Gear(2).Eigenvalues(),
   278  		},
   279  		{
   280  			a:      Gear(3).Matrix(),
   281  			evWant: Gear(3).Eigenvalues(),
   282  		},
   283  		{
   284  			a:      Gear(4).Matrix(),
   285  			evWant: Gear(4).Eigenvalues(),
   286  			valTol: 1e-7,
   287  		},
   288  		{
   289  			a:      Gear(5).Matrix(),
   290  			evWant: Gear(5).Eigenvalues(),
   291  		},
   292  		{
   293  			a:      Gear(10).Matrix(),
   294  			evWant: Gear(10).Eigenvalues(),
   295  			valTol: 1e-8,
   296  		},
   297  		{
   298  			a:      Gear(15).Matrix(),
   299  			evWant: Gear(15).Eigenvalues(),
   300  		},
   301  		{
   302  			a:      Gear(30).Matrix(),
   303  			evWant: Gear(30).Eigenvalues(),
   304  			valTol: 1e-8,
   305  		},
   306  		{
   307  			a:      Gear(50).Matrix(),
   308  			evWant: Gear(50).Eigenvalues(),
   309  			valTol: 1e-8,
   310  		},
   311  		{
   312  			a:      Gear(101).Matrix(),
   313  			evWant: Gear(101).Eigenvalues(),
   314  		},
   315  		{
   316  			a:      Gear(150).Matrix(),
   317  			evWant: Gear(150).Eigenvalues(),
   318  			valTol: 1e-8,
   319  		},
   320  
   321  		{
   322  			a:      Grcar{N: 10, K: 3}.Matrix(),
   323  			evWant: Grcar{N: 10, K: 3}.Eigenvalues(),
   324  		},
   325  		{
   326  			a:      Grcar{N: 10, K: 7}.Matrix(),
   327  			evWant: Grcar{N: 10, K: 7}.Eigenvalues(),
   328  		},
   329  		{
   330  			a:      Grcar{N: 11, K: 7}.Matrix(),
   331  			evWant: Grcar{N: 11, K: 7}.Eigenvalues(),
   332  		},
   333  		{
   334  			a:      Grcar{N: 50, K: 3}.Matrix(),
   335  			evWant: Grcar{N: 50, K: 3}.Eigenvalues(),
   336  		},
   337  		{
   338  			a:      Grcar{N: 51, K: 3}.Matrix(),
   339  			evWant: Grcar{N: 51, K: 3}.Eigenvalues(),
   340  		},
   341  		{
   342  			a:      Grcar{N: 50, K: 10}.Matrix(),
   343  			evWant: Grcar{N: 50, K: 10}.Eigenvalues(),
   344  		},
   345  		{
   346  			a:      Grcar{N: 51, K: 10}.Matrix(),
   347  			evWant: Grcar{N: 51, K: 10}.Eigenvalues(),
   348  		},
   349  		{
   350  			a:      Grcar{N: 50, K: 30}.Matrix(),
   351  			evWant: Grcar{N: 50, K: 30}.Eigenvalues(),
   352  		},
   353  		{
   354  			a:      Grcar{N: 150, K: 2}.Matrix(),
   355  			evWant: Grcar{N: 150, K: 2}.Eigenvalues(),
   356  		},
   357  		{
   358  			a:      Grcar{N: 150, K: 148}.Matrix(),
   359  			evWant: Grcar{N: 150, K: 148}.Eigenvalues(),
   360  		},
   361  
   362  		{
   363  			a:      Hanowa{N: 6, Alpha: 17}.Matrix(),
   364  			evWant: Hanowa{N: 6, Alpha: 17}.Eigenvalues(),
   365  		},
   366  		{
   367  			a:      Hanowa{N: 50, Alpha: -1}.Matrix(),
   368  			evWant: Hanowa{N: 50, Alpha: -1}.Eigenvalues(),
   369  		},
   370  		{
   371  			a:      Hanowa{N: 100, Alpha: -1}.Matrix(),
   372  			evWant: Hanowa{N: 100, Alpha: -1}.Eigenvalues(),
   373  		},
   374  
   375  		{
   376  			a:      Lesp(2).Matrix(),
   377  			evWant: Lesp(2).Eigenvalues(),
   378  		},
   379  		{
   380  			a:      Lesp(3).Matrix(),
   381  			evWant: Lesp(3).Eigenvalues(),
   382  		},
   383  		{
   384  			a:      Lesp(4).Matrix(),
   385  			evWant: Lesp(4).Eigenvalues(),
   386  		},
   387  		{
   388  			a:      Lesp(5).Matrix(),
   389  			evWant: Lesp(5).Eigenvalues(),
   390  		},
   391  		{
   392  			a:      Lesp(10).Matrix(),
   393  			evWant: Lesp(10).Eigenvalues(),
   394  		},
   395  		{
   396  			a:      Lesp(15).Matrix(),
   397  			evWant: Lesp(15).Eigenvalues(),
   398  		},
   399  		{
   400  			a:      Lesp(30).Matrix(),
   401  			evWant: Lesp(30).Eigenvalues(),
   402  		},
   403  		{
   404  			a:      Lesp(50).Matrix(),
   405  			evWant: Lesp(50).Eigenvalues(),
   406  			valTol: 1e-12,
   407  			vecTol: 1e-12,
   408  		},
   409  		{
   410  			a:      Lesp(101).Matrix(),
   411  			evWant: Lesp(101).Eigenvalues(),
   412  			valTol: 1e-12,
   413  			vecTol: 1e-12,
   414  		},
   415  		{
   416  			a:      Lesp(150).Matrix(),
   417  			evWant: Lesp(150).Eigenvalues(),
   418  			valTol: 1e-12,
   419  			vecTol: 1e-12,
   420  		},
   421  
   422  		{
   423  			a:      Rutis{}.Matrix(),
   424  			evWant: Rutis{}.Eigenvalues(),
   425  		},
   426  
   427  		{
   428  			a:      Tris{N: 74, X: 1, Y: -2, Z: 1}.Matrix(),
   429  			evWant: Tris{N: 74, X: 1, Y: -2, Z: 1}.Eigenvalues(),
   430  		},
   431  		{
   432  			a:      Tris{N: 74, X: 1, Y: 2, Z: -3}.Matrix(),
   433  			evWant: Tris{N: 74, X: 1, Y: 2, Z: -3}.Eigenvalues(),
   434  		},
   435  		{
   436  			a:      Tris{N: 75, X: 1, Y: 2, Z: -3}.Matrix(),
   437  			evWant: Tris{N: 75, X: 1, Y: 2, Z: -3}.Eigenvalues(),
   438  		},
   439  
   440  		{
   441  			a:      Wilk4{}.Matrix(),
   442  			evWant: Wilk4{}.Eigenvalues(),
   443  		},
   444  		{
   445  			a:      Wilk12{}.Matrix(),
   446  			evWant: Wilk12{}.Eigenvalues(),
   447  			valTol: 1e-8,
   448  		},
   449  		{
   450  			a:      Wilk20(0).Matrix(),
   451  			evWant: Wilk20(0).Eigenvalues(),
   452  		},
   453  		{
   454  			a:      Wilk20(1e-10).Matrix(),
   455  			evWant: Wilk20(1e-10).Eigenvalues(),
   456  			valTol: 1e-12,
   457  			vecTol: 1e-12,
   458  		},
   459  
   460  		{
   461  			a:      Zero(1).Matrix(),
   462  			evWant: Zero(1).Eigenvalues(),
   463  		},
   464  		{
   465  			a:      Zero(10).Matrix(),
   466  			evWant: Zero(10).Eigenvalues(),
   467  		},
   468  		{
   469  			a:      Zero(50).Matrix(),
   470  			evWant: Zero(50).Eigenvalues(),
   471  		},
   472  		{
   473  			a:      Zero(100).Matrix(),
   474  			evWant: Zero(100).Eigenvalues(),
   475  		},
   476  	} {
   477  		for _, jobvl := range []lapack.LeftEVJob{lapack.ComputeLeftEV, lapack.None} {
   478  			for _, jobvr := range []lapack.RightEVJob{lapack.ComputeRightEV, lapack.None} {
   479  				for _, extra := range []int{0, 11} {
   480  					for _, wl := range []worklen{minimumWork, mediumWork, optimumWork} {
   481  						testDgeev(t, impl, strconv.Itoa(i), test, jobvl, jobvr, extra, wl)
   482  					}
   483  				}
   484  			}
   485  		}
   486  	}
   487  
   488  	for _, n := range []int{2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 20, 50, 51, 100, 101} {
   489  		for _, jobvl := range []lapack.LeftEVJob{lapack.ComputeLeftEV, lapack.None} {
   490  			for _, jobvr := range []lapack.RightEVJob{lapack.ComputeRightEV, lapack.None} {
   491  				for cas := 0; cas < 10; cas++ {
   492  					// Create a block diagonal matrix with
   493  					// random eigenvalues of random multiplicity.
   494  					ev := make([]complex128, n)
   495  					tmat := zeros(n, n, n)
   496  					for i := 0; i < n; {
   497  						re := rnd.NormFloat64()
   498  						if i == n-1 || rnd.Float64() < 0.5 {
   499  							// Real eigenvalue.
   500  							nb := rnd.Intn(min(4, n-i)) + 1
   501  							for k := 0; k < nb; k++ {
   502  								tmat.Data[i*tmat.Stride+i] = re
   503  								ev[i] = complex(re, 0)
   504  								i++
   505  							}
   506  							continue
   507  						}
   508  						// Complex eigenvalue.
   509  						im := rnd.NormFloat64()
   510  						nb := rnd.Intn(min(4, (n-i)/2)) + 1
   511  						for k := 0; k < nb; k++ {
   512  							// 2×2 block for the complex eigenvalue.
   513  							tmat.Data[i*tmat.Stride+i] = re
   514  							tmat.Data[(i+1)*tmat.Stride+i+1] = re
   515  							tmat.Data[(i+1)*tmat.Stride+i] = -im
   516  							tmat.Data[i*tmat.Stride+i+1] = im
   517  							ev[i] = complex(re, im)
   518  							ev[i+1] = complex(re, -im)
   519  							i += 2
   520  						}
   521  					}
   522  
   523  					// Compute A = Q T Q^T where Q is an
   524  					// orthogonal matrix.
   525  					q := randomOrthogonal(n, rnd)
   526  					tq := zeros(n, n, n)
   527  					blas64.Gemm(blas.NoTrans, blas.Trans, 1, tmat, q, 0, tq)
   528  					a := zeros(n, n, n)
   529  					blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, q, tq, 0, a)
   530  
   531  					test := dgeevTest{
   532  						a:      a,
   533  						evWant: ev,
   534  						valTol: 1e-12,
   535  						vecTol: 1e-8,
   536  					}
   537  					testDgeev(t, impl, "random", test, jobvl, jobvr, 0, optimumWork)
   538  				}
   539  			}
   540  		}
   541  	}
   542  }
   543  
   544  func testDgeev(t *testing.T, impl Dgeever, tc string, test dgeevTest, jobvl lapack.LeftEVJob, jobvr lapack.RightEVJob, extra int, wl worklen) {
   545  	const defaultTol = 1e-13
   546  	valTol := test.valTol
   547  	if valTol == 0 {
   548  		valTol = defaultTol
   549  	}
   550  	vecTol := test.vecTol
   551  	if vecTol == 0 {
   552  		vecTol = defaultTol
   553  	}
   554  
   555  	a := cloneGeneral(test.a)
   556  	n := a.Rows
   557  
   558  	var vl blas64.General
   559  	if jobvl == lapack.ComputeLeftEV {
   560  		vl = nanGeneral(n, n, n)
   561  	}
   562  
   563  	var vr blas64.General
   564  	if jobvr == lapack.ComputeRightEV {
   565  		vr = nanGeneral(n, n, n)
   566  	}
   567  
   568  	wr := make([]float64, n)
   569  	wi := make([]float64, n)
   570  
   571  	var lwork int
   572  	switch wl {
   573  	case minimumWork:
   574  		if jobvl == lapack.ComputeLeftEV || jobvr == lapack.ComputeRightEV {
   575  			lwork = max(1, 4*n)
   576  		} else {
   577  			lwork = max(1, 3*n)
   578  		}
   579  	case mediumWork:
   580  		work := make([]float64, 1)
   581  		impl.Dgeev(jobvl, jobvr, n, nil, 1, nil, nil, nil, 1, nil, 1, work, -1)
   582  		if jobvl == lapack.ComputeLeftEV || jobvr == lapack.ComputeRightEV {
   583  			lwork = (int(work[0]) + 4*n) / 2
   584  		} else {
   585  			lwork = (int(work[0]) + 3*n) / 2
   586  		}
   587  		lwork = max(1, lwork)
   588  	case optimumWork:
   589  		work := make([]float64, 1)
   590  		impl.Dgeev(jobvl, jobvr, n, nil, 1, nil, nil, nil, 1, nil, 1, work, -1)
   591  		lwork = int(work[0])
   592  	}
   593  	work := make([]float64, lwork)
   594  
   595  	first := impl.Dgeev(jobvl, jobvr, n, a.Data, a.Stride, wr, wi,
   596  		vl.Data, vl.Stride, vr.Data, vr.Stride, work, len(work))
   597  
   598  	prefix := fmt.Sprintf("Case #%v: n=%v, jobvl=%v, jobvr=%v, extra=%v, work=%v",
   599  		tc, n, jobvl, jobvr, extra, wl)
   600  
   601  	if !generalOutsideAllNaN(vl) {
   602  		t.Errorf("%v: out-of-range write to VL", prefix)
   603  	}
   604  	if !generalOutsideAllNaN(vr) {
   605  		t.Errorf("%v: out-of-range write to VR", prefix)
   606  	}
   607  
   608  	if first > 0 {
   609  		t.Log("%v: all eigenvalues haven't been computed, first=%v", prefix, first)
   610  	}
   611  
   612  	// Check that conjugate pair eigevalues are ordered correctly.
   613  	for i := first; i < n; {
   614  		if wi[i] == 0 {
   615  			i++
   616  			continue
   617  		}
   618  		if wr[i] != wr[i+1] {
   619  			t.Errorf("%v: real parts of %vth conjugate pair not equal", prefix, i)
   620  		}
   621  		if wi[i] < 0 || wi[i+1] > 0 {
   622  			t.Errorf("%v: unexpected ordering of %vth conjugate pair", prefix, i)
   623  		}
   624  		i += 2
   625  	}
   626  
   627  	// Check the computed eigenvalues against provided known eigenvalues.
   628  	if test.evWant != nil {
   629  		used := make([]bool, n)
   630  		for i := first; i < n; i++ {
   631  			evGot := complex(wr[i], wi[i])
   632  			idx := -1
   633  			for k, evWant := range test.evWant {
   634  				if !used[k] && cmplx.Abs(evWant-evGot) < valTol {
   635  					idx = k
   636  					used[k] = true
   637  					break
   638  				}
   639  			}
   640  			if idx == -1 {
   641  				t.Errorf("%v: unexpected eigenvalue %v", prefix, evGot)
   642  			}
   643  		}
   644  	}
   645  
   646  	if first > 0 || (jobvl == lapack.None && jobvr == lapack.None) {
   647  		// No eigenvectors have been computed.
   648  		return
   649  	}
   650  
   651  	// Check that the columns of VL and VR are eigenvectors that correspond
   652  	// to the computed eigenvalues.
   653  	for k := 0; k < n; {
   654  		if wi[k] == 0 {
   655  			if jobvl == lapack.ComputeLeftEV {
   656  				ev := columnOf(vl, k)
   657  				if !isLeftEigenvectorOf(test.a, ev, nil, complex(wr[k], 0), vecTol) {
   658  					t.Errorf("%v: VL[:,%v] is not left real eigenvector",
   659  						prefix, k)
   660  				}
   661  
   662  				norm := floats.Norm(ev, 2)
   663  				if math.Abs(norm-1) >= defaultTol {
   664  					t.Errorf("%v: norm of left real eigenvector %v not equal to 1: got %v",
   665  						prefix, k, norm)
   666  				}
   667  			}
   668  			if jobvr == lapack.ComputeRightEV {
   669  				ev := columnOf(vr, k)
   670  				if !isRightEigenvectorOf(test.a, ev, nil, complex(wr[k], 0), vecTol) {
   671  					t.Errorf("%v: VR[:,%v] is not right real eigenvector",
   672  						prefix, k)
   673  				}
   674  
   675  				norm := floats.Norm(ev, 2)
   676  				if math.Abs(norm-1) >= defaultTol {
   677  					t.Errorf("%v: norm of right real eigenvector %v not equal to 1: got %v",
   678  						prefix, k, norm)
   679  				}
   680  			}
   681  			k++
   682  		} else {
   683  			if jobvl == lapack.ComputeLeftEV {
   684  				evre := columnOf(vl, k)
   685  				evim := columnOf(vl, k+1)
   686  				if !isLeftEigenvectorOf(test.a, evre, evim, complex(wr[k], wi[k]), vecTol) {
   687  					t.Errorf("%v: VL[:,%v:%v] is not left complex eigenvector",
   688  						prefix, k, k+1)
   689  				}
   690  				floats.Scale(-1, evim)
   691  				if !isLeftEigenvectorOf(test.a, evre, evim, complex(wr[k+1], wi[k+1]), vecTol) {
   692  					t.Errorf("%v: VL[:,%v:%v] is not left complex eigenvector",
   693  						prefix, k, k+1)
   694  				}
   695  
   696  				norm := math.Hypot(floats.Norm(evre, 2), floats.Norm(evim, 2))
   697  				if math.Abs(norm-1) > defaultTol {
   698  					t.Errorf("%v: norm of left complex eigenvector %v not equal to 1: got %v",
   699  						prefix, k, norm)
   700  				}
   701  			}
   702  			if jobvr == lapack.ComputeRightEV {
   703  				evre := columnOf(vr, k)
   704  				evim := columnOf(vr, k+1)
   705  				if !isRightEigenvectorOf(test.a, evre, evim, complex(wr[k], wi[k]), vecTol) {
   706  					t.Errorf("%v: VR[:,%v:%v] is not right complex eigenvector",
   707  						prefix, k, k+1)
   708  				}
   709  				floats.Scale(-1, evim)
   710  				if !isRightEigenvectorOf(test.a, evre, evim, complex(wr[k+1], wi[k+1]), vecTol) {
   711  					t.Errorf("%v: VR[:,%v:%v] is not right complex eigenvector",
   712  						prefix, k, k+1)
   713  				}
   714  
   715  				norm := math.Hypot(floats.Norm(evre, 2), floats.Norm(evim, 2))
   716  				if math.Abs(norm-1) > defaultTol {
   717  					t.Errorf("%v: norm of right complex eigenvector %v not equal to 1: got %v",
   718  						prefix, k, norm)
   719  				}
   720  			}
   721  			// We don't test whether the largest component is real
   722  			// because checking it is flaky due to rounding errors.
   723  
   724  			k += 2
   725  		}
   726  	}
   727  }
   728  
   729  func dgeevTestForAntisymRandom(n int, rnd *rand.Rand) dgeevTest {
   730  	a := NewAntisymRandom(n, rnd)
   731  	return dgeevTest{
   732  		a:      a.Matrix(),
   733  		evWant: a.Eigenvalues(),
   734  	}
   735  }