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 }