gonum.org/v1/gonum@v0.14.0/lapack/testlapack/test_matrices.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 "math" 9 10 "golang.org/x/exp/rand" 11 12 "gonum.org/v1/gonum/blas/blas64" 13 ) 14 15 // A123 is the non-symmetric singular matrix 16 // 17 // [ 1 2 3 ] 18 // A = [ 4 5 6 ] 19 // [ 7 8 9 ] 20 // 21 // It has three distinct real eigenvalues. 22 type A123 struct{} 23 24 func (A123) Matrix() blas64.General { 25 return blas64.General{ 26 Rows: 3, 27 Cols: 3, 28 Stride: 3, 29 Data: []float64{ 30 1, 2, 3, 31 4, 5, 6, 32 7, 8, 9, 33 }, 34 } 35 } 36 37 func (A123) Eigenvalues() []complex128 { 38 return []complex128{16.116843969807043, -1.116843969807043, 0} 39 } 40 41 func (A123) LeftEV() blas64.General { 42 return blas64.General{ 43 Rows: 3, 44 Cols: 3, 45 Stride: 3, 46 Data: []float64{ 47 -0.464547273387671, -0.570795531228578, -0.677043789069485, 48 -0.882905959653586, -0.239520420054206, 0.403865119545174, 49 0.408248290463862, -0.816496580927726, 0.408248290463863, 50 }, 51 } 52 } 53 54 func (A123) RightEV() blas64.General { 55 return blas64.General{ 56 Rows: 3, 57 Cols: 3, 58 Stride: 3, 59 Data: []float64{ 60 -0.231970687246286, -0.785830238742067, 0.408248290463864, 61 -0.525322093301234, -0.086751339256628, -0.816496580927726, 62 -0.818673499356181, 0.612327560228810, 0.408248290463863, 63 }, 64 } 65 } 66 67 // AntisymRandom is a anti-symmetric random matrix. All its eigenvalues are 68 // imaginary with one zero if the order is odd. 69 type AntisymRandom struct { 70 mat blas64.General 71 } 72 73 func NewAntisymRandom(n int, rnd *rand.Rand) AntisymRandom { 74 a := zeros(n, n, n) 75 for i := 0; i < n; i++ { 76 for j := i + 1; j < n; j++ { 77 r := rnd.NormFloat64() 78 a.Data[i*a.Stride+j] = r 79 a.Data[j*a.Stride+i] = -r 80 } 81 } 82 return AntisymRandom{a} 83 } 84 85 func (a AntisymRandom) Matrix() blas64.General { 86 return cloneGeneral(a.mat) 87 } 88 89 func (AntisymRandom) Eigenvalues() []complex128 { 90 return nil 91 } 92 93 // Circulant is a generally non-symmetric matrix given by 94 // 95 // A[i,j] = 1 + (j-i+n)%n. 96 // 97 // For example, for n=5, 98 // 99 // [ 1 2 3 4 5 ] 100 // [ 5 1 2 3 4 ] 101 // A = [ 4 5 1 2 3 ] 102 // [ 3 4 5 1 2 ] 103 // [ 2 3 4 5 1 ] 104 // 105 // It has real and complex eigenvalues, some possibly repeated. 106 type Circulant int 107 108 func (c Circulant) Matrix() blas64.General { 109 n := int(c) 110 a := zeros(n, n, n) 111 for i := 0; i < n; i++ { 112 for j := 0; j < n; j++ { 113 a.Data[i*a.Stride+j] = float64(1 + (j-i+n)%n) 114 } 115 } 116 return a 117 } 118 119 func (c Circulant) Eigenvalues() []complex128 { 120 n := int(c) 121 w := rootsOfUnity(n) 122 ev := make([]complex128, n) 123 for k := 0; k < n; k++ { 124 ev[k] = complex(float64(n), 0) 125 } 126 for i := n - 1; i > 0; i-- { 127 for k := 0; k < n; k++ { 128 ev[k] = ev[k]*w[k] + complex(float64(i), 0) 129 } 130 } 131 return ev 132 } 133 134 // Clement is a generally non-symmetric matrix given by 135 // 136 // A[i,j] = i+1 if j == i+1, 137 // = n-i if j == i-1, 138 // = 0 otherwise. 139 // 140 // For example, for n=5, 141 // 142 // [ . 1 . . . ] 143 // [ 4 . 2 . . ] 144 // A = [ . 3 . 3 . ] 145 // [ . . 2 . 4 ] 146 // [ . . . 1 . ] 147 // 148 // It has n distinct real eigenvalues. 149 type Clement int 150 151 func (c Clement) Matrix() blas64.General { 152 n := int(c) 153 a := zeros(n, n, n) 154 for i := 0; i < n; i++ { 155 if i < n-1 { 156 a.Data[i*a.Stride+i+1] = float64(i + 1) 157 } 158 if i > 0 { 159 a.Data[i*a.Stride+i-1] = float64(n - i) 160 } 161 } 162 return a 163 } 164 165 func (c Clement) Eigenvalues() []complex128 { 166 n := int(c) 167 ev := make([]complex128, n) 168 for i := range ev { 169 ev[i] = complex(float64(-n+2*i+1), 0) 170 } 171 return ev 172 } 173 174 // Creation is a singular non-symmetric matrix given by 175 // 176 // A[i,j] = i if j == i-1, 177 // = 0 otherwise. 178 // 179 // For example, for n=5, 180 // 181 // [ . . . . . ] 182 // [ 1 . . . . ] 183 // A = [ . 2 . . . ] 184 // [ . . 3 . . ] 185 // [ . . . 4 . ] 186 // 187 // Zero is its only eigenvalue. 188 type Creation int 189 190 func (c Creation) Matrix() blas64.General { 191 n := int(c) 192 a := zeros(n, n, n) 193 for i := 1; i < n; i++ { 194 a.Data[i*a.Stride+i-1] = float64(i) 195 } 196 return a 197 } 198 199 func (c Creation) Eigenvalues() []complex128 { 200 return make([]complex128, int(c)) 201 } 202 203 // Diagonal is a diagonal matrix given by 204 // 205 // A[i,j] = i+1 if i == j, 206 // = 0 otherwise. 207 // 208 // For example, for n=5, 209 // 210 // [ 1 . . . . ] 211 // [ . 2 . . . ] 212 // A = [ . . 3 . . ] 213 // [ . . . 4 . ] 214 // [ . . . . 5 ] 215 // 216 // It has n real eigenvalues {1,...,n}. 217 type Diagonal int 218 219 func (d Diagonal) Matrix() blas64.General { 220 n := int(d) 221 a := zeros(n, n, n) 222 for i := 0; i < n; i++ { 223 a.Data[i*a.Stride+i] = float64(i) 224 } 225 return a 226 } 227 228 func (d Diagonal) Eigenvalues() []complex128 { 229 n := int(d) 230 ev := make([]complex128, n) 231 for i := range ev { 232 ev[i] = complex(float64(i), 0) 233 } 234 return ev 235 } 236 237 // Downshift is a non-singular upper Hessenberg matrix given by 238 // 239 // A[i,j] = 1 if (i-j+n)%n == 1, 240 // = 0 otherwise. 241 // 242 // For example, for n=5, 243 // 244 // [ . . . . 1 ] 245 // [ 1 . . . . ] 246 // A = [ . 1 . . . ] 247 // [ . . 1 . . ] 248 // [ . . . 1 . ] 249 // 250 // Its eigenvalues are the complex roots of unity. 251 type Downshift int 252 253 func (d Downshift) Matrix() blas64.General { 254 n := int(d) 255 a := zeros(n, n, n) 256 a.Data[n-1] = 1 257 for i := 1; i < n; i++ { 258 a.Data[i*a.Stride+i-1] = 1 259 } 260 return a 261 } 262 263 func (d Downshift) Eigenvalues() []complex128 { 264 return rootsOfUnity(int(d)) 265 } 266 267 // Fibonacci is an upper Hessenberg matrix with 3 distinct real eigenvalues. For 268 // example, for n=5, 269 // 270 // [ . 1 . . . ] 271 // [ 1 1 . . . ] 272 // A = [ . 1 1 . . ] 273 // [ . . 1 1 . ] 274 // [ . . . 1 1 ] 275 type Fibonacci int 276 277 func (f Fibonacci) Matrix() blas64.General { 278 n := int(f) 279 a := zeros(n, n, n) 280 if n > 1 { 281 a.Data[1] = 1 282 } 283 for i := 1; i < n; i++ { 284 a.Data[i*a.Stride+i-1] = 1 285 a.Data[i*a.Stride+i] = 1 286 } 287 return a 288 } 289 290 func (f Fibonacci) Eigenvalues() []complex128 { 291 n := int(f) 292 ev := make([]complex128, n) 293 if n == 0 || n == 1 { 294 return ev 295 } 296 phi := 0.5 * (1 + math.Sqrt(5)) 297 ev[0] = complex(phi, 0) 298 for i := 1; i < n-1; i++ { 299 ev[i] = 1 + 0i 300 } 301 ev[n-1] = complex(1-phi, 0) 302 return ev 303 } 304 305 // Gear is a singular non-symmetric matrix with real eigenvalues. For example, 306 // for n=5, 307 // 308 // [ . 1 . . 1 ] 309 // [ 1 . 1 . . ] 310 // A = [ . 1 . 1 . ] 311 // [ . . 1 . 1 ] 312 // [-1 . . 1 . ] 313 type Gear int 314 315 func (g Gear) Matrix() blas64.General { 316 n := int(g) 317 a := zeros(n, n, n) 318 if n == 1 { 319 return a 320 } 321 for i := 0; i < n-1; i++ { 322 a.Data[i*a.Stride+i+1] = 1 323 } 324 for i := 1; i < n; i++ { 325 a.Data[i*a.Stride+i-1] = 1 326 } 327 a.Data[n-1] = 1 328 a.Data[(n-1)*a.Stride] = -1 329 return a 330 } 331 332 func (g Gear) Eigenvalues() []complex128 { 333 n := int(g) 334 ev := make([]complex128, n) 335 if n == 0 || n == 1 { 336 return ev 337 } 338 if n == 2 { 339 ev[0] = complex(0, 1) 340 ev[1] = complex(0, -1) 341 return ev 342 } 343 w := 0 344 ev[w] = math.Pi / 2 345 w++ 346 phi := (n - 1) / 2 347 for p := 1; p <= phi; p++ { 348 ev[w] = complex(float64(2*p)*math.Pi/float64(n), 0) 349 w++ 350 } 351 phi = n / 2 352 for p := 1; p <= phi; p++ { 353 ev[w] = complex(float64(2*p-1)*math.Pi/float64(n), 0) 354 w++ 355 } 356 for i, v := range ev { 357 ev[i] = complex(2*math.Cos(real(v)), 0) 358 } 359 return ev 360 } 361 362 // Grcar is an upper Hessenberg matrix given by 363 // 364 // A[i,j] = -1 if i == j+1, 365 // = 1 if i <= j and j <= i+k, 366 // = 0 otherwise. 367 // 368 // For example, for n=5 and k=2, 369 // 370 // [ 1 1 1 . . ] 371 // [ -1 1 1 1 . ] 372 // A = [ . -1 1 1 1 ] 373 // [ . . -1 1 1 ] 374 // [ . . . -1 1 ] 375 // 376 // The matrix has sensitive eigenvalues but they are not given explicitly. 377 type Grcar struct { 378 N int 379 K int 380 } 381 382 func (g Grcar) Matrix() blas64.General { 383 n := g.N 384 a := zeros(n, n, n) 385 for k := 0; k <= g.K; k++ { 386 for i := 0; i < n-k; i++ { 387 a.Data[i*a.Stride+i+k] = 1 388 } 389 } 390 for i := 1; i < n; i++ { 391 a.Data[i*a.Stride+i-1] = -1 392 } 393 return a 394 } 395 396 func (Grcar) Eigenvalues() []complex128 { 397 return nil 398 } 399 400 // Hanowa is a non-symmetric non-singular matrix of even order given by 401 // 402 // A[i,j] = alpha if i == j, 403 // = -i-1 if i < n/2 and j == i + n/2, 404 // = i+1-n/2 if i >= n/2 and j == i - n/2, 405 // = 0 otherwise. 406 // 407 // The matrix has complex eigenvalues. 408 type Hanowa struct { 409 N int // Order of the matrix, must be even. 410 Alpha float64 411 } 412 413 func (h Hanowa) Matrix() blas64.General { 414 if h.N&0x1 != 0 { 415 panic("lapack: matrix order must be even") 416 } 417 n := h.N 418 a := zeros(n, n, n) 419 for i := 0; i < n; i++ { 420 a.Data[i*a.Stride+i] = h.Alpha 421 } 422 for i := 0; i < n/2; i++ { 423 a.Data[i*a.Stride+i+n/2] = float64(-i - 1) 424 } 425 for i := n / 2; i < n; i++ { 426 a.Data[i*a.Stride+i-n/2] = float64(i + 1 - n/2) 427 } 428 return a 429 } 430 431 func (h Hanowa) Eigenvalues() []complex128 { 432 if h.N&0x1 != 0 { 433 panic("lapack: matrix order must be even") 434 } 435 n := h.N 436 ev := make([]complex128, n) 437 for i := 0; i < n/2; i++ { 438 ev[2*i] = complex(h.Alpha, float64(-i-1)) 439 ev[2*i+1] = complex(h.Alpha, float64(i+1)) 440 } 441 return ev 442 } 443 444 // Lesp is a tridiagonal, generally non-symmetric matrix given by 445 // 446 // A[i,j] = -2*i-5 if i == j, 447 // = 1/(i+1) if i == j-1, 448 // = j+1 if i == j+1. 449 // 450 // For example, for n=5, 451 // 452 // [ -5 2 . . . ] 453 // [ 1/2 -7 3 . . ] 454 // A = [ . 1/3 -9 4 . ] 455 // [ . . 1/4 -11 5 ] 456 // [ . . . 1/5 -13 ]. 457 // 458 // The matrix has sensitive eigenvalues but they are not given explicitly. 459 type Lesp int 460 461 func (l Lesp) Matrix() blas64.General { 462 n := int(l) 463 a := zeros(n, n, n) 464 for i := 0; i < n; i++ { 465 a.Data[i*a.Stride+i] = float64(-2*i - 5) 466 } 467 for i := 0; i < n-1; i++ { 468 a.Data[i*a.Stride+i+1] = float64(i + 2) 469 } 470 for i := 1; i < n; i++ { 471 a.Data[i*a.Stride+i-1] = 1 / float64(i+1) 472 } 473 return a 474 } 475 476 func (Lesp) Eigenvalues() []complex128 { 477 return nil 478 } 479 480 // Rutis is the 4×4 non-symmetric matrix 481 // 482 // [ 4 -5 0 3 ] 483 // A = [ 0 4 -3 -5 ] 484 // [ 5 -3 4 0 ] 485 // [ 3 0 5 4 ] 486 // 487 // It has two distinct real eigenvalues and a pair of complex eigenvalues. 488 type Rutis struct{} 489 490 func (Rutis) Matrix() blas64.General { 491 return blas64.General{ 492 Rows: 4, 493 Cols: 4, 494 Stride: 4, 495 Data: []float64{ 496 4, -5, 0, 3, 497 0, 4, -3, -5, 498 5, -3, 4, 0, 499 3, 0, 5, 4, 500 }, 501 } 502 } 503 504 func (Rutis) Eigenvalues() []complex128 { 505 return []complex128{12, 1 + 5i, 1 - 5i, 2} 506 } 507 508 // Tris is a tridiagonal matrix given by 509 // 510 // A[i,j] = x if i == j-1, 511 // = y if i == j, 512 // = z if i == j+1. 513 // 514 // If x*z is negative, the matrix has complex eigenvalues. 515 type Tris struct { 516 N int 517 X, Y, Z float64 518 } 519 520 func (t Tris) Matrix() blas64.General { 521 n := t.N 522 a := zeros(n, n, n) 523 for i := 1; i < n; i++ { 524 a.Data[i*a.Stride+i-1] = t.X 525 } 526 for i := 0; i < n; i++ { 527 a.Data[i*a.Stride+i] = t.Y 528 } 529 for i := 0; i < n-1; i++ { 530 a.Data[i*a.Stride+i+1] = t.Z 531 } 532 return a 533 } 534 535 func (t Tris) Eigenvalues() []complex128 { 536 n := t.N 537 ev := make([]complex128, n) 538 for i := range ev { 539 angle := float64(i+1) * math.Pi / float64(n+1) 540 arg := t.X * t.Z 541 if arg >= 0 { 542 ev[i] = complex(t.Y+2*math.Sqrt(arg)*math.Cos(angle), 0) 543 } else { 544 ev[i] = complex(t.Y, 2*math.Sqrt(-arg)*math.Cos(angle)) 545 } 546 } 547 return ev 548 } 549 550 // Wilk4 is a 4×4 lower triangular matrix with 4 distinct real eigenvalues. 551 type Wilk4 struct{} 552 553 func (Wilk4) Matrix() blas64.General { 554 return blas64.General{ 555 Rows: 4, 556 Cols: 4, 557 Stride: 4, 558 Data: []float64{ 559 0.9143e-4, 0.0, 0.0, 0.0, 560 0.8762, 0.7156e-4, 0.0, 0.0, 561 0.7943, 0.8143, 0.9504e-4, 0.0, 562 0.8017, 0.6123, 0.7165, 0.7123e-4, 563 }, 564 } 565 } 566 567 func (Wilk4) Eigenvalues() []complex128 { 568 return []complex128{ 569 0.9504e-4, 0.9143e-4, 0.7156e-4, 0.7123e-4, 570 } 571 } 572 573 // Wilk12 is a 12×12 lower Hessenberg matrix with 12 distinct real eigenvalues. 574 type Wilk12 struct{} 575 576 func (Wilk12) Matrix() blas64.General { 577 return blas64.General{ 578 Rows: 12, 579 Cols: 12, 580 Stride: 12, 581 Data: []float64{ 582 12, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 583 11, 11, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 584 10, 10, 10, 9, 0, 0, 0, 0, 0, 0, 0, 0, 585 9, 9, 9, 9, 8, 0, 0, 0, 0, 0, 0, 0, 586 8, 8, 8, 8, 8, 7, 0, 0, 0, 0, 0, 0, 587 7, 7, 7, 7, 7, 7, 6, 0, 0, 0, 0, 0, 588 6, 6, 6, 6, 6, 6, 6, 5, 0, 0, 0, 0, 589 5, 5, 5, 5, 5, 5, 5, 5, 4, 0, 0, 0, 590 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 0, 0, 591 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 0, 592 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 593 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 594 }, 595 } 596 } 597 598 func (Wilk12) Eigenvalues() []complex128 { 599 return []complex128{ 600 32.2288915015722210, 601 20.1989886458770691, 602 12.3110774008685340, 603 6.9615330855671154, 604 3.5118559485807528, 605 1.5539887091319704, 606 0.6435053190136506, 607 0.2847497205488856, 608 0.1436465181918488, 609 0.0812276683076552, 610 0.0495074140194613, 611 0.0310280683208907, 612 } 613 } 614 615 // Wilk20 is a 20×20 lower Hessenberg matrix. If the parameter is 0, the matrix 616 // has 20 distinct real eigenvalues. If the parameter is 1e-10, the matrix has 6 617 // real eigenvalues and 7 pairs of complex eigenvalues. 618 type Wilk20 float64 619 620 func (w Wilk20) Matrix() blas64.General { 621 a := zeros(20, 20, 20) 622 for i := 0; i < 20; i++ { 623 a.Data[i*a.Stride+i] = float64(i + 1) 624 } 625 for i := 0; i < 19; i++ { 626 a.Data[i*a.Stride+i+1] = 20 627 } 628 a.Data[19*a.Stride] = float64(w) 629 return a 630 } 631 632 func (w Wilk20) Eigenvalues() []complex128 { 633 if float64(w) == 0 { 634 ev := make([]complex128, 20) 635 for i := range ev { 636 ev[i] = complex(float64(i+1), 0) 637 } 638 return ev 639 } 640 return nil 641 } 642 643 // Zero is a matrix with all elements equal to zero. 644 type Zero int 645 646 func (z Zero) Matrix() blas64.General { 647 n := int(z) 648 return zeros(n, n, n) 649 } 650 651 func (z Zero) Eigenvalues() []complex128 { 652 n := int(z) 653 return make([]complex128, n) 654 }