github.com/gopherd/gonum@v0.0.4/lapack/testlapack/general.go (about) 1 // Copyright ©2015 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 "testing" 12 13 "math/rand" 14 15 "github.com/gopherd/gonum/blas" 16 "github.com/gopherd/gonum/blas/blas64" 17 "github.com/gopherd/gonum/lapack" 18 ) 19 20 const ( 21 // dlamchE is the machine epsilon. For IEEE this is 2^{-53}. 22 dlamchE = 0x1p-53 23 dlamchB = 2 24 dlamchP = dlamchB * dlamchE 25 // dlamchS is the smallest normal number. For IEEE this is 2^{-1022}. 26 dlamchS = 0x1p-1022 27 28 safmin = dlamchS 29 safmax = 1 / safmin 30 ulp = dlamchP 31 smlnum = safmin / ulp 32 bignum = safmax * ulp 33 ) 34 35 func max(a, b int) int { 36 if a > b { 37 return a 38 } 39 return b 40 } 41 42 func min(a, b int) int { 43 if a < b { 44 return a 45 } 46 return b 47 } 48 49 // worklen describes how much workspace a test should use. 50 type worklen int 51 52 const ( 53 minimumWork worklen = iota 54 mediumWork 55 optimumWork 56 ) 57 58 func (wl worklen) String() string { 59 switch wl { 60 case minimumWork: 61 return "minimum" 62 case mediumWork: 63 return "medium" 64 case optimumWork: 65 return "optimum" 66 } 67 return "" 68 } 69 70 func normToString(norm lapack.MatrixNorm) string { 71 switch norm { 72 case lapack.MaxAbs: 73 return "MaxAbs" 74 case lapack.MaxRowSum: 75 return "MaxRowSum" 76 case lapack.MaxColumnSum: 77 return "MaxColSum" 78 case lapack.Frobenius: 79 return "Frobenius" 80 default: 81 panic("invalid norm") 82 } 83 } 84 85 func uploToString(uplo blas.Uplo) string { 86 switch uplo { 87 case blas.Lower: 88 return "Lower" 89 case blas.Upper: 90 return "Upper" 91 default: 92 panic("invalid uplo") 93 } 94 } 95 96 func diagToString(diag blas.Diag) string { 97 switch diag { 98 case blas.NonUnit: 99 return "NonUnit" 100 case blas.Unit: 101 return "Unit" 102 default: 103 panic("invalid diag") 104 } 105 } 106 107 func sideToString(side blas.Side) string { 108 switch side { 109 case blas.Left: 110 return "Left" 111 case blas.Right: 112 return "Right" 113 default: 114 panic("invalid side") 115 } 116 } 117 118 func transToString(trans blas.Transpose) string { 119 switch trans { 120 case blas.NoTrans: 121 return "NoTrans" 122 case blas.Trans: 123 return "Trans" 124 case blas.ConjTrans: 125 return "ConjTrans" 126 default: 127 panic("invalid trans") 128 } 129 } 130 131 // nanSlice allocates a new slice of length n filled with NaN. 132 func nanSlice(n int) []float64 { 133 s := make([]float64, n) 134 for i := range s { 135 s[i] = math.NaN() 136 } 137 return s 138 } 139 140 // randomSlice allocates a new slice of length n filled with random values. 141 func randomSlice(n int, rnd *rand.Rand) []float64 { 142 s := make([]float64, n) 143 for i := range s { 144 s[i] = rnd.NormFloat64() 145 } 146 return s 147 } 148 149 // nanGeneral allocates a new r×c general matrix filled with NaN values. 150 func nanGeneral(r, c, stride int) blas64.General { 151 if r < 0 || c < 0 { 152 panic("bad matrix size") 153 } 154 if r == 0 || c == 0 { 155 return blas64.General{Stride: max(1, stride)} 156 } 157 if stride < c { 158 panic("bad stride") 159 } 160 return blas64.General{ 161 Rows: r, 162 Cols: c, 163 Stride: stride, 164 Data: nanSlice((r-1)*stride + c), 165 } 166 } 167 168 // randomGeneral allocates a new r×c general matrix filled with random 169 // numbers. Out-of-range elements are filled with NaN values. 170 func randomGeneral(r, c, stride int, rnd *rand.Rand) blas64.General { 171 ans := nanGeneral(r, c, stride) 172 for i := 0; i < r; i++ { 173 for j := 0; j < c; j++ { 174 ans.Data[i*ans.Stride+j] = rnd.NormFloat64() 175 } 176 } 177 return ans 178 } 179 180 // randomHessenberg allocates a new n×n Hessenberg matrix filled with zeros 181 // under the first subdiagonal and with random numbers elsewhere. Out-of-range 182 // elements are filled with NaN values. 183 func randomHessenberg(n, stride int, rnd *rand.Rand) blas64.General { 184 ans := nanGeneral(n, n, stride) 185 for i := 0; i < n; i++ { 186 for j := 0; j < i-1; j++ { 187 ans.Data[i*ans.Stride+j] = 0 188 } 189 for j := max(0, i-1); j < n; j++ { 190 ans.Data[i*ans.Stride+j] = rnd.NormFloat64() 191 } 192 } 193 return ans 194 } 195 196 // randomSchurCanonical returns a random, general matrix in Schur canonical 197 // form, that is, block upper triangular with 1×1 and 2×2 diagonal blocks where 198 // each 2×2 diagonal block has its diagonal elements equal and its off-diagonal 199 // elements of opposite sign. bad controls whether the returned matrix will have 200 // zero or tiny eigenvalues. 201 func randomSchurCanonical(n, stride int, bad bool, rnd *rand.Rand) (t blas64.General, wr, wi []float64) { 202 t = randomGeneral(n, n, stride, rnd) 203 // Zero out the lower triangle including the diagonal which will be set later. 204 for i := 0; i < t.Rows; i++ { 205 for j := 0; j <= i; j++ { 206 t.Data[i*t.Stride+j] = 0 207 } 208 } 209 // Randomly create 2×2 diagonal blocks. 210 for i := 0; i < t.Rows; { 211 a := rnd.NormFloat64() 212 if bad && rnd.Float64() < 0.5 { 213 if rnd.Float64() < 0.5 { 214 // A quarter of real parts of eigenvalues will be tiny. 215 a = dlamchS 216 } else { 217 // A quarter of them will be zero. 218 a = 0 219 } 220 } 221 222 // A half of eigenvalues will be real. 223 if rnd.Float64() < 0.5 || i == t.Rows-1 { 224 // Store 1×1 block at the diagonal of T. 225 t.Data[i*t.Stride+i] = a 226 wr = append(wr, a) 227 wi = append(wi, 0) 228 i++ 229 continue 230 } 231 232 // Diagonal elements are equal. 233 d := a 234 // Element under the diagonal is "normal". 235 c := rnd.NormFloat64() 236 // Element above the diagonal cannot be zero. 237 var b float64 238 if bad && rnd.Float64() < 0.5 { 239 b = dlamchS 240 } else { 241 b = rnd.NormFloat64() 242 } 243 // Make sure off-diagonal elements are of opposite sign. 244 if math.Signbit(b) == math.Signbit(c) { 245 c *= -1 246 } 247 248 // Store 2×2 block at the diagonal of T. 249 t.Data[i*t.Stride+i], t.Data[i*t.Stride+i+1] = a, b 250 t.Data[(i+1)*t.Stride+i], t.Data[(i+1)*t.Stride+i+1] = c, d 251 252 wr = append(wr, a, a) 253 im := math.Sqrt(math.Abs(b)) * math.Sqrt(math.Abs(c)) 254 wi = append(wi, im, -im) 255 i += 2 256 } 257 return t, wr, wi 258 } 259 260 // blockedUpperTriGeneral returns a normal random, general matrix in the form 261 // 262 // c-k-l k l 263 // A = k [ 0 A12 A13 ] if r-k-l >= 0; 264 // l [ 0 0 A23 ] 265 // r-k-l [ 0 0 0 ] 266 // 267 // c-k-l k l 268 // A = k [ 0 A12 A13 ] if r-k-l < 0; 269 // r-k [ 0 0 A23 ] 270 // 271 // where the k×k matrix A12 and l×l matrix is non-singular 272 // upper triangular. A23 is l×l upper triangular if r-k-l >= 0, 273 // otherwise A23 is (r-k)×l upper trapezoidal. 274 func blockedUpperTriGeneral(r, c, k, l, stride int, kblock bool, rnd *rand.Rand) blas64.General { 275 t := l 276 if kblock { 277 t += k 278 } 279 ans := zeros(r, c, stride) 280 for i := 0; i < min(r, t); i++ { 281 var v float64 282 for v == 0 { 283 v = rnd.NormFloat64() 284 } 285 ans.Data[i*ans.Stride+i+(c-t)] = v 286 } 287 for i := 0; i < min(r, t); i++ { 288 for j := i + (c - t) + 1; j < c; j++ { 289 ans.Data[i*ans.Stride+j] = rnd.NormFloat64() 290 } 291 } 292 return ans 293 } 294 295 // nanTriangular allocates a new r×c triangular matrix filled with NaN values. 296 func nanTriangular(uplo blas.Uplo, n, stride int) blas64.Triangular { 297 if n < 0 { 298 panic("bad matrix size") 299 } 300 if n == 0 { 301 return blas64.Triangular{ 302 Stride: max(1, stride), 303 Uplo: uplo, 304 Diag: blas.NonUnit, 305 } 306 } 307 if stride < n { 308 panic("bad stride") 309 } 310 return blas64.Triangular{ 311 N: n, 312 Stride: stride, 313 Data: nanSlice((n-1)*stride + n), 314 Uplo: uplo, 315 Diag: blas.NonUnit, 316 } 317 } 318 319 // generalOutsideAllNaN returns whether all out-of-range elements have NaN 320 // values. 321 func generalOutsideAllNaN(a blas64.General) bool { 322 // Check after last column. 323 for i := 0; i < a.Rows-1; i++ { 324 for _, v := range a.Data[i*a.Stride+a.Cols : i*a.Stride+a.Stride] { 325 if !math.IsNaN(v) { 326 return false 327 } 328 } 329 } 330 // Check after last element. 331 last := (a.Rows-1)*a.Stride + a.Cols 332 if a.Rows == 0 || a.Cols == 0 { 333 last = 0 334 } 335 for _, v := range a.Data[last:] { 336 if !math.IsNaN(v) { 337 return false 338 } 339 } 340 return true 341 } 342 343 // triangularOutsideAllNaN returns whether all out-of-triangle elements have NaN 344 // values. 345 func triangularOutsideAllNaN(a blas64.Triangular) bool { 346 if a.Uplo == blas.Upper { 347 // Check below diagonal. 348 for i := 0; i < a.N; i++ { 349 for _, v := range a.Data[i*a.Stride : i*a.Stride+i] { 350 if !math.IsNaN(v) { 351 return false 352 } 353 } 354 } 355 // Check after last column. 356 for i := 0; i < a.N-1; i++ { 357 for _, v := range a.Data[i*a.Stride+a.N : i*a.Stride+a.Stride] { 358 if !math.IsNaN(v) { 359 return false 360 } 361 } 362 } 363 } else { 364 // Check above diagonal. 365 for i := 0; i < a.N-1; i++ { 366 for _, v := range a.Data[i*a.Stride+i+1 : i*a.Stride+a.Stride] { 367 if !math.IsNaN(v) { 368 return false 369 } 370 } 371 } 372 } 373 // Check after last element. 374 for _, v := range a.Data[max(0, a.N-1)*a.Stride+a.N:] { 375 if !math.IsNaN(v) { 376 return false 377 } 378 } 379 return true 380 } 381 382 // transposeGeneral returns a new general matrix that is the transpose of the 383 // input. Nothing is done with data outside the {rows, cols} limit of the general. 384 func transposeGeneral(a blas64.General) blas64.General { 385 ans := blas64.General{ 386 Rows: a.Cols, 387 Cols: a.Rows, 388 Stride: a.Rows, 389 Data: make([]float64, a.Cols*a.Rows), 390 } 391 for i := 0; i < a.Rows; i++ { 392 for j := 0; j < a.Cols; j++ { 393 ans.Data[j*ans.Stride+i] = a.Data[i*a.Stride+j] 394 } 395 } 396 return ans 397 } 398 399 // columnNorms returns the column norms of a. 400 func columnNorms(m, n int, a []float64, lda int) []float64 { 401 bi := blas64.Implementation() 402 norms := make([]float64, n) 403 for j := 0; j < n; j++ { 404 norms[j] = bi.Dnrm2(m, a[j:], lda) 405 } 406 return norms 407 } 408 409 // extractVMat collects the single reflectors from a into a matrix. 410 func extractVMat(m, n int, a []float64, lda int, direct lapack.Direct, store lapack.StoreV) blas64.General { 411 k := min(m, n) 412 switch { 413 default: 414 panic("not implemented") 415 case direct == lapack.Forward && store == lapack.ColumnWise: 416 v := blas64.General{ 417 Rows: m, 418 Cols: k, 419 Stride: k, 420 Data: make([]float64, m*k), 421 } 422 for i := 0; i < k; i++ { 423 for j := 0; j < i; j++ { 424 v.Data[j*v.Stride+i] = 0 425 } 426 v.Data[i*v.Stride+i] = 1 427 for j := i + 1; j < m; j++ { 428 v.Data[j*v.Stride+i] = a[j*lda+i] 429 } 430 } 431 return v 432 case direct == lapack.Forward && store == lapack.RowWise: 433 v := blas64.General{ 434 Rows: k, 435 Cols: n, 436 Stride: n, 437 Data: make([]float64, k*n), 438 } 439 for i := 0; i < k; i++ { 440 for j := 0; j < i; j++ { 441 v.Data[i*v.Stride+j] = 0 442 } 443 v.Data[i*v.Stride+i] = 1 444 for j := i + 1; j < n; j++ { 445 v.Data[i*v.Stride+j] = a[i*lda+j] 446 } 447 } 448 return v 449 } 450 } 451 452 // constructBidiagonal constructs a bidiagonal matrix with the given diagonal 453 // and off-diagonal elements. 454 func constructBidiagonal(uplo blas.Uplo, n int, d, e []float64) blas64.General { 455 bMat := blas64.General{ 456 Rows: n, 457 Cols: n, 458 Stride: n, 459 Data: make([]float64, n*n), 460 } 461 462 for i := 0; i < n-1; i++ { 463 bMat.Data[i*bMat.Stride+i] = d[i] 464 if uplo == blas.Upper { 465 bMat.Data[i*bMat.Stride+i+1] = e[i] 466 } else { 467 bMat.Data[(i+1)*bMat.Stride+i] = e[i] 468 } 469 } 470 bMat.Data[(n-1)*bMat.Stride+n-1] = d[n-1] 471 return bMat 472 } 473 474 // constructVMat transforms the v matrix based on the storage. 475 func constructVMat(vMat blas64.General, store lapack.StoreV, direct lapack.Direct) blas64.General { 476 m := vMat.Rows 477 k := vMat.Cols 478 switch { 479 default: 480 panic("not implemented") 481 case store == lapack.ColumnWise && direct == lapack.Forward: 482 ldv := k 483 v := make([]float64, m*k) 484 for i := 0; i < m; i++ { 485 for j := 0; j < k; j++ { 486 if j > i { 487 v[i*ldv+j] = 0 488 } else if j == i { 489 v[i*ldv+i] = 1 490 } else { 491 v[i*ldv+j] = vMat.Data[i*vMat.Stride+j] 492 } 493 } 494 } 495 return blas64.General{ 496 Rows: m, 497 Cols: k, 498 Stride: k, 499 Data: v, 500 } 501 case store == lapack.RowWise && direct == lapack.Forward: 502 ldv := m 503 v := make([]float64, m*k) 504 for i := 0; i < m; i++ { 505 for j := 0; j < k; j++ { 506 if j > i { 507 v[j*ldv+i] = 0 508 } else if j == i { 509 v[j*ldv+i] = 1 510 } else { 511 v[j*ldv+i] = vMat.Data[i*vMat.Stride+j] 512 } 513 } 514 } 515 return blas64.General{ 516 Rows: k, 517 Cols: m, 518 Stride: m, 519 Data: v, 520 } 521 case store == lapack.ColumnWise && direct == lapack.Backward: 522 rowsv := m 523 ldv := k 524 v := make([]float64, m*k) 525 for i := 0; i < m; i++ { 526 for j := 0; j < k; j++ { 527 vrow := rowsv - i - 1 528 vcol := k - j - 1 529 if j > i { 530 v[vrow*ldv+vcol] = 0 531 } else if j == i { 532 v[vrow*ldv+vcol] = 1 533 } else { 534 v[vrow*ldv+vcol] = vMat.Data[i*vMat.Stride+j] 535 } 536 } 537 } 538 return blas64.General{ 539 Rows: rowsv, 540 Cols: ldv, 541 Stride: ldv, 542 Data: v, 543 } 544 case store == lapack.RowWise && direct == lapack.Backward: 545 rowsv := k 546 ldv := m 547 v := make([]float64, m*k) 548 for i := 0; i < m; i++ { 549 for j := 0; j < k; j++ { 550 vcol := ldv - i - 1 551 vrow := k - j - 1 552 if j > i { 553 v[vrow*ldv+vcol] = 0 554 } else if j == i { 555 v[vrow*ldv+vcol] = 1 556 } else { 557 v[vrow*ldv+vcol] = vMat.Data[i*vMat.Stride+j] 558 } 559 } 560 } 561 return blas64.General{ 562 Rows: rowsv, 563 Cols: ldv, 564 Stride: ldv, 565 Data: v, 566 } 567 } 568 } 569 570 func constructH(tau []float64, v blas64.General, store lapack.StoreV, direct lapack.Direct) blas64.General { 571 m := v.Rows 572 k := v.Cols 573 if store == lapack.RowWise { 574 m, k = k, m 575 } 576 h := blas64.General{ 577 Rows: m, 578 Cols: m, 579 Stride: m, 580 Data: make([]float64, m*m), 581 } 582 for i := 0; i < m; i++ { 583 h.Data[i*m+i] = 1 584 } 585 for i := 0; i < k; i++ { 586 vecData := make([]float64, m) 587 if store == lapack.ColumnWise { 588 for j := 0; j < m; j++ { 589 vecData[j] = v.Data[j*v.Cols+i] 590 } 591 } else { 592 for j := 0; j < m; j++ { 593 vecData[j] = v.Data[i*v.Cols+j] 594 } 595 } 596 vec := blas64.Vector{ 597 Inc: 1, 598 Data: vecData, 599 } 600 601 hi := blas64.General{ 602 Rows: m, 603 Cols: m, 604 Stride: m, 605 Data: make([]float64, m*m), 606 } 607 for i := 0; i < m; i++ { 608 hi.Data[i*m+i] = 1 609 } 610 // hi = I - tau * v * vᵀ 611 blas64.Ger(-tau[i], vec, vec, hi) 612 613 hcopy := blas64.General{ 614 Rows: m, 615 Cols: m, 616 Stride: m, 617 Data: make([]float64, m*m), 618 } 619 copy(hcopy.Data, h.Data) 620 if direct == lapack.Forward { 621 // H = H * H_I in forward mode 622 blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, hcopy, hi, 0, h) 623 } else { 624 // H = H_I * H in backward mode 625 blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, hi, hcopy, 0, h) 626 } 627 } 628 return h 629 } 630 631 // constructQ constructs the Q matrix from the result of dgeqrf and dgeqr2. 632 func constructQ(kind string, m, n int, a []float64, lda int, tau []float64) blas64.General { 633 k := min(m, n) 634 return constructQK(kind, m, n, k, a, lda, tau) 635 } 636 637 // constructQK constructs the Q matrix from the result of dgeqrf and dgeqr2 using 638 // the first k reflectors. 639 func constructQK(kind string, m, n, k int, a []float64, lda int, tau []float64) blas64.General { 640 var sz int 641 switch kind { 642 case "QR": 643 sz = m 644 case "LQ", "RQ": 645 sz = n 646 } 647 648 q := blas64.General{ 649 Rows: sz, 650 Cols: sz, 651 Stride: max(1, sz), 652 Data: make([]float64, sz*sz), 653 } 654 for i := 0; i < sz; i++ { 655 q.Data[i*sz+i] = 1 656 } 657 qCopy := blas64.General{ 658 Rows: q.Rows, 659 Cols: q.Cols, 660 Stride: q.Stride, 661 Data: make([]float64, len(q.Data)), 662 } 663 for i := 0; i < k; i++ { 664 h := blas64.General{ 665 Rows: sz, 666 Cols: sz, 667 Stride: max(1, sz), 668 Data: make([]float64, sz*sz), 669 } 670 for j := 0; j < sz; j++ { 671 h.Data[j*sz+j] = 1 672 } 673 vVec := blas64.Vector{ 674 Inc: 1, 675 Data: make([]float64, sz), 676 } 677 switch kind { 678 case "QR": 679 vVec.Data[i] = 1 680 for j := i + 1; j < sz; j++ { 681 vVec.Data[j] = a[lda*j+i] 682 } 683 case "LQ": 684 vVec.Data[i] = 1 685 for j := i + 1; j < sz; j++ { 686 vVec.Data[j] = a[i*lda+j] 687 } 688 case "RQ": 689 for j := 0; j < n-k+i; j++ { 690 vVec.Data[j] = a[(m-k+i)*lda+j] 691 } 692 vVec.Data[n-k+i] = 1 693 } 694 blas64.Ger(-tau[i], vVec, vVec, h) 695 copy(qCopy.Data, q.Data) 696 // Multiply q by the new h. 697 switch kind { 698 case "QR", "RQ": 699 blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, qCopy, h, 0, q) 700 case "LQ": 701 blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, h, qCopy, 0, q) 702 } 703 } 704 return q 705 } 706 707 // checkBidiagonal checks the bidiagonal decomposition from dlabrd and dgebd2. 708 // The input to this function is the answer returned from the routines, stored 709 // in a, d, e, tauP, and tauQ. The data of original A matrix (before 710 // decomposition) is input in aCopy. 711 // 712 // checkBidiagonal constructs the V and U matrices, and from them constructs Q 713 // and P. Using these constructions, it checks that Qᵀ * A * P and checks that 714 // the result is bidiagonal. 715 func checkBidiagonal(t *testing.T, m, n, nb int, a []float64, lda int, d, e, tauP, tauQ, aCopy []float64) { 716 // Check the answer. 717 // Construct V and U. 718 qMat := constructQPBidiagonal(lapack.ApplyQ, m, n, nb, a, lda, tauQ) 719 pMat := constructQPBidiagonal(lapack.ApplyP, m, n, nb, a, lda, tauP) 720 721 // Compute Qᵀ * A * P. 722 aMat := blas64.General{ 723 Rows: m, 724 Cols: n, 725 Stride: lda, 726 Data: make([]float64, len(aCopy)), 727 } 728 copy(aMat.Data, aCopy) 729 730 tmp1 := blas64.General{ 731 Rows: m, 732 Cols: n, 733 Stride: n, 734 Data: make([]float64, m*n), 735 } 736 blas64.Gemm(blas.Trans, blas.NoTrans, 1, qMat, aMat, 0, tmp1) 737 tmp2 := blas64.General{ 738 Rows: m, 739 Cols: n, 740 Stride: n, 741 Data: make([]float64, m*n), 742 } 743 blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, tmp1, pMat, 0, tmp2) 744 745 // Check that the first nb rows and cols of tm2 are upper bidiagonal 746 // if m >= n, and lower bidiagonal otherwise. 747 correctDiag := true 748 matchD := true 749 matchE := true 750 for i := 0; i < m; i++ { 751 for j := 0; j < n; j++ { 752 if i >= nb && j >= nb { 753 continue 754 } 755 v := tmp2.Data[i*tmp2.Stride+j] 756 if i == j { 757 if math.Abs(d[i]-v) > 1e-12 { 758 matchD = false 759 } 760 continue 761 } 762 if m >= n && i == j-1 { 763 if math.Abs(e[j-1]-v) > 1e-12 { 764 matchE = false 765 } 766 continue 767 } 768 if m < n && i-1 == j { 769 if math.Abs(e[i-1]-v) > 1e-12 { 770 matchE = false 771 } 772 continue 773 } 774 if math.Abs(v) > 1e-12 { 775 correctDiag = false 776 } 777 } 778 } 779 if !correctDiag { 780 t.Errorf("Updated A not bi-diagonal") 781 } 782 if !matchD { 783 fmt.Println("d = ", d) 784 t.Errorf("D Mismatch") 785 } 786 if !matchE { 787 t.Errorf("E mismatch") 788 } 789 } 790 791 // constructQPBidiagonal constructs Q or P from the Bidiagonal decomposition 792 // computed by dlabrd and bgebd2. 793 func constructQPBidiagonal(vect lapack.ApplyOrtho, m, n, nb int, a []float64, lda int, tau []float64) blas64.General { 794 sz := n 795 if vect == lapack.ApplyQ { 796 sz = m 797 } 798 799 var ldv int 800 var v blas64.General 801 if vect == lapack.ApplyQ { 802 ldv = nb 803 v = blas64.General{ 804 Rows: m, 805 Cols: nb, 806 Stride: ldv, 807 Data: make([]float64, m*ldv), 808 } 809 } else { 810 ldv = n 811 v = blas64.General{ 812 Rows: nb, 813 Cols: n, 814 Stride: ldv, 815 Data: make([]float64, m*ldv), 816 } 817 } 818 819 if vect == lapack.ApplyQ { 820 if m >= n { 821 for i := 0; i < m; i++ { 822 for j := 0; j <= min(nb-1, i); j++ { 823 if i == j { 824 v.Data[i*ldv+j] = 1 825 continue 826 } 827 v.Data[i*ldv+j] = a[i*lda+j] 828 } 829 } 830 } else { 831 for i := 1; i < m; i++ { 832 for j := 0; j <= min(nb-1, i-1); j++ { 833 if i-1 == j { 834 v.Data[i*ldv+j] = 1 835 continue 836 } 837 v.Data[i*ldv+j] = a[i*lda+j] 838 } 839 } 840 } 841 } else { 842 if m < n { 843 for i := 0; i < nb; i++ { 844 for j := i; j < n; j++ { 845 if i == j { 846 v.Data[i*ldv+j] = 1 847 continue 848 } 849 v.Data[i*ldv+j] = a[i*lda+j] 850 } 851 } 852 } else { 853 for i := 0; i < nb; i++ { 854 for j := i + 1; j < n; j++ { 855 if j-1 == i { 856 v.Data[i*ldv+j] = 1 857 continue 858 } 859 v.Data[i*ldv+j] = a[i*lda+j] 860 } 861 } 862 } 863 } 864 865 // The variable name is a computation of Q, but the algorithm is mostly the 866 // same for computing P (just with different data). 867 qMat := blas64.General{ 868 Rows: sz, 869 Cols: sz, 870 Stride: sz, 871 Data: make([]float64, sz*sz), 872 } 873 hMat := blas64.General{ 874 Rows: sz, 875 Cols: sz, 876 Stride: sz, 877 Data: make([]float64, sz*sz), 878 } 879 // set Q to I 880 for i := 0; i < sz; i++ { 881 qMat.Data[i*qMat.Stride+i] = 1 882 } 883 for i := 0; i < nb; i++ { 884 qCopy := blas64.General{Rows: qMat.Rows, Cols: qMat.Cols, Stride: qMat.Stride, Data: make([]float64, len(qMat.Data))} 885 copy(qCopy.Data, qMat.Data) 886 887 // Set g and h to I 888 for i := 0; i < sz; i++ { 889 for j := 0; j < sz; j++ { 890 if i == j { 891 hMat.Data[i*sz+j] = 1 892 } else { 893 hMat.Data[i*sz+j] = 0 894 } 895 } 896 } 897 var vi blas64.Vector 898 // H -= tauQ[i] * v[i] * v[i]^t 899 if vect == lapack.ApplyQ { 900 vi = blas64.Vector{ 901 Inc: v.Stride, 902 Data: v.Data[i:], 903 } 904 } else { 905 vi = blas64.Vector{ 906 Inc: 1, 907 Data: v.Data[i*v.Stride:], 908 } 909 } 910 blas64.Ger(-tau[i], vi, vi, hMat) 911 // Q = Q * G[1] 912 blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, qCopy, hMat, 0, qMat) 913 } 914 return qMat 915 } 916 917 // printRowise prints the matrix with one row per line. This is useful for debugging. 918 // If beyond is true, it prints beyond the final column to lda. If false, only 919 // the columns are printed. 920 //nolint:deadcode,unused 921 func printRowise(a []float64, m, n, lda int, beyond bool) { 922 for i := 0; i < m; i++ { 923 end := n 924 if beyond { 925 end = lda 926 } 927 fmt.Println(a[i*lda : i*lda+end]) 928 } 929 } 930 931 func copyGeneral(dst, src blas64.General) { 932 r := min(dst.Rows, src.Rows) 933 c := min(dst.Cols, src.Cols) 934 for i := 0; i < r; i++ { 935 copy(dst.Data[i*dst.Stride:i*dst.Stride+c], src.Data[i*src.Stride:i*src.Stride+c]) 936 } 937 } 938 939 // cloneGeneral allocates and returns an exact copy of the given general matrix. 940 func cloneGeneral(a blas64.General) blas64.General { 941 c := a 942 c.Data = make([]float64, len(a.Data)) 943 copy(c.Data, a.Data) 944 return c 945 } 946 947 // equalGeneral returns whether the general matrices a and b are equal. 948 func equalGeneral(a, b blas64.General) bool { 949 if a.Rows != b.Rows || a.Cols != b.Cols { 950 panic("bad input") 951 } 952 for i := 0; i < a.Rows; i++ { 953 for j := 0; j < a.Cols; j++ { 954 if a.Data[i*a.Stride+j] != b.Data[i*b.Stride+j] { 955 return false 956 } 957 } 958 } 959 return true 960 } 961 962 // equalApproxGeneral returns whether the general matrices a and b are 963 // approximately equal within given tolerance. 964 func equalApproxGeneral(a, b blas64.General, tol float64) bool { 965 if a.Rows != b.Rows || a.Cols != b.Cols { 966 panic("bad input") 967 } 968 for i := 0; i < a.Rows; i++ { 969 for j := 0; j < a.Cols; j++ { 970 diff := a.Data[i*a.Stride+j] - b.Data[i*b.Stride+j] 971 if math.IsNaN(diff) || math.Abs(diff) > tol { 972 return false 973 } 974 } 975 } 976 return true 977 } 978 979 func intsEqual(a, b []int) bool { 980 if len(a) != len(b) { 981 return false 982 } 983 for i, ai := range a { 984 if b[i] != ai { 985 return false 986 } 987 } 988 return true 989 } 990 991 // randSymBand returns an n×n random symmetric positive definite band matrix 992 // with kd diagonals. 993 func randSymBand(uplo blas.Uplo, n, kd, ldab int, rnd *rand.Rand) []float64 { 994 // Allocate a triangular band matrix U or L and fill it with random numbers. 995 var ab []float64 996 if n > 0 { 997 ab = make([]float64, (n-1)*ldab+kd+1) 998 } 999 for i := range ab { 1000 ab[i] = rnd.NormFloat64() 1001 } 1002 // Make sure that the matrix U or L has a sufficiently positive diagonal. 1003 switch uplo { 1004 case blas.Upper: 1005 for i := 0; i < n; i++ { 1006 ab[i*ldab] = float64(n) + rnd.Float64() 1007 } 1008 case blas.Lower: 1009 for i := 0; i < n; i++ { 1010 ab[i*ldab+kd] = float64(n) + rnd.Float64() 1011 } 1012 } 1013 // Compute Uᵀ*U or L*Lᵀ. The resulting (symmetric) matrix A will be 1014 // positive definite and well-conditioned. 1015 dsbmm(uplo, n, kd, ab, ldab) 1016 return ab 1017 } 1018 1019 // distSymBand returns the max-norm distance between the symmetric band matrices 1020 // A and B. 1021 func distSymBand(uplo blas.Uplo, n, kd int, a []float64, lda int, b []float64, ldb int) float64 { 1022 var dist float64 1023 switch uplo { 1024 case blas.Upper: 1025 for i := 0; i < n; i++ { 1026 for j := 0; j < min(kd+1, n-i); j++ { 1027 dist = math.Max(dist, math.Abs(a[i*lda+j]-b[i*ldb+j])) 1028 } 1029 } 1030 case blas.Lower: 1031 for i := 0; i < n; i++ { 1032 for j := max(0, kd-i); j < kd+1; j++ { 1033 dist = math.Max(dist, math.Abs(a[i*lda+j]-b[i*ldb+j])) 1034 } 1035 } 1036 } 1037 return dist 1038 } 1039 1040 // eye returns an identity matrix of given order and stride. 1041 func eye(n, stride int) blas64.General { 1042 ans := nanGeneral(n, n, stride) 1043 for i := 0; i < n; i++ { 1044 for j := 0; j < n; j++ { 1045 ans.Data[i*ans.Stride+j] = 0 1046 } 1047 ans.Data[i*ans.Stride+i] = 1 1048 } 1049 return ans 1050 } 1051 1052 // zeros returns an m×n matrix with given stride filled with zeros. 1053 func zeros(m, n, stride int) blas64.General { 1054 a := nanGeneral(m, n, stride) 1055 for i := 0; i < m; i++ { 1056 for j := 0; j < n; j++ { 1057 a.Data[i*a.Stride+j] = 0 1058 } 1059 } 1060 return a 1061 } 1062 1063 // extract2x2Block returns the elements of T at [0,0], [0,1], [1,0], and [1,1]. 1064 func extract2x2Block(t []float64, ldt int) (a, b, c, d float64) { 1065 return t[0], t[1], t[ldt], t[ldt+1] 1066 } 1067 1068 // isSchurCanonical returns whether the 2×2 matrix [a b; c d] is in Schur 1069 // canonical form. 1070 func isSchurCanonical(a, b, c, d float64) bool { 1071 return c == 0 || (b != 0 && a == d && math.Signbit(b) != math.Signbit(c)) 1072 } 1073 1074 // isSchurCanonicalGeneral returns whether T is block upper triangular with 1×1 1075 // and 2×2 diagonal blocks, each 2×2 block in Schur canonical form. The function 1076 // checks only along the diagonal and the first subdiagonal, otherwise the lower 1077 // triangle is not accessed. 1078 func isSchurCanonicalGeneral(t blas64.General) bool { 1079 n := t.Cols 1080 if t.Rows != n { 1081 panic("invalid matrix") 1082 } 1083 for j := 0; j < n-1; { 1084 if t.Data[(j+1)*t.Stride+j] == 0 { 1085 // 1×1 block. 1086 for i := j + 1; i < n; i++ { 1087 if t.Data[i*t.Stride+j] != 0 { 1088 return false 1089 } 1090 } 1091 j++ 1092 continue 1093 } 1094 // 2×2 block. 1095 a, b, c, d := extract2x2Block(t.Data[j*t.Stride+j:], t.Stride) 1096 if !isSchurCanonical(a, b, c, d) { 1097 return false 1098 } 1099 for i := j + 2; i < n; i++ { 1100 if t.Data[i*t.Stride+j] != 0 { 1101 return false 1102 } 1103 } 1104 for i := j + 2; i < n; i++ { 1105 if t.Data[i*t.Stride+j+1] != 0 { 1106 return false 1107 } 1108 } 1109 j += 2 1110 } 1111 return true 1112 } 1113 1114 // schurBlockEigenvalues returns the two eigenvalues of the 2×2 matrix [a b; c d] 1115 // that must be in Schur canonical form. 1116 func schurBlockEigenvalues(a, b, c, d float64) (ev1, ev2 complex128) { 1117 if !isSchurCanonical(a, b, c, d) { 1118 panic("block not in Schur canonical form") 1119 } 1120 if c == 0 { 1121 return complex(a, 0), complex(d, 0) 1122 } 1123 im := math.Sqrt(math.Abs(b)) * math.Sqrt(math.Abs(c)) 1124 return complex(a, im), complex(a, -im) 1125 } 1126 1127 // schurBlockSize returns the size of the diagonal block at i-th row in the 1128 // upper quasi-triangular matrix t in Schur canonical form, and whether i points 1129 // to the first row of the block. For zero-sized matrices the function returns 0 1130 // and true. 1131 func schurBlockSize(t blas64.General, i int) (size int, first bool) { 1132 if t.Rows != t.Cols { 1133 panic("matrix not square") 1134 } 1135 if t.Rows == 0 { 1136 return 0, true 1137 } 1138 if i < 0 || t.Rows <= i { 1139 panic("index out of range") 1140 } 1141 1142 first = true 1143 if i > 0 && t.Data[i*t.Stride+i-1] != 0 { 1144 // There is a non-zero element to the left, therefore i must 1145 // point to the second row in a 2×2 diagonal block. 1146 first = false 1147 i-- 1148 } 1149 size = 1 1150 if i+1 < t.Rows && t.Data[(i+1)*t.Stride+i] != 0 { 1151 // There is a non-zero element below, this must be a 2×2 1152 // diagonal block. 1153 size = 2 1154 } 1155 return size, first 1156 } 1157 1158 // containsComplex returns whether z is approximately equal to one of the complex 1159 // numbers in v. If z is found, its index in v will be also returned. 1160 func containsComplex(v []complex128, z complex128, tol float64) (found bool, index int) { 1161 for i := range v { 1162 if cmplx.Abs(v[i]-z) < tol { 1163 return true, i 1164 } 1165 } 1166 return false, -1 1167 } 1168 1169 // isAllNaN returns whether x contains only NaN values. 1170 func isAllNaN(x []float64) bool { 1171 for _, v := range x { 1172 if !math.IsNaN(v) { 1173 return false 1174 } 1175 } 1176 return true 1177 } 1178 1179 // isUpperHessenberg returns whether h contains only zeros below the 1180 // subdiagonal. 1181 func isUpperHessenberg(h blas64.General) bool { 1182 if h.Rows != h.Cols { 1183 panic("matrix not square") 1184 } 1185 n := h.Rows 1186 for i := 0; i < n; i++ { 1187 for j := 0; j < n; j++ { 1188 if i > j+1 && h.Data[i*h.Stride+j] != 0 { 1189 return false 1190 } 1191 } 1192 } 1193 return true 1194 } 1195 1196 // isUpperTriangular returns whether a contains only zeros below the diagonal. 1197 func isUpperTriangular(a blas64.General) bool { 1198 n := a.Rows 1199 for i := 1; i < n; i++ { 1200 for j := 0; j < i; j++ { 1201 if a.Data[i*a.Stride+j] != 0 { 1202 return false 1203 } 1204 } 1205 } 1206 return true 1207 } 1208 1209 // unbalancedSparseGeneral returns an m×n dense matrix with a random sparse 1210 // structure consisting of nz nonzero elements. The matrix will be unbalanced by 1211 // multiplying each element randomly by its row or column index. 1212 func unbalancedSparseGeneral(m, n, stride int, nonzeros int, rnd *rand.Rand) blas64.General { 1213 a := zeros(m, n, stride) 1214 for k := 0; k < nonzeros; k++ { 1215 i := rnd.Intn(n) 1216 j := rnd.Intn(n) 1217 if rnd.Float64() < 0.5 { 1218 a.Data[i*stride+j] = float64(i+1) * rnd.NormFloat64() 1219 } else { 1220 a.Data[i*stride+j] = float64(j+1) * rnd.NormFloat64() 1221 } 1222 } 1223 return a 1224 } 1225 1226 // rootsOfUnity returns the n complex numbers whose n-th power is equal to 1. 1227 func rootsOfUnity(n int) []complex128 { 1228 w := make([]complex128, n) 1229 for i := 0; i < n; i++ { 1230 angle := math.Pi * float64(2*i) / float64(n) 1231 w[i] = complex(math.Cos(angle), math.Sin(angle)) 1232 } 1233 return w 1234 } 1235 1236 // constructGSVDresults returns the matrices [ 0 R ], D1 and D2 described 1237 // in the documentation of Dtgsja and Dggsvd3, and the result matrix in 1238 // the documentation for Dggsvp3. 1239 func constructGSVDresults(n, p, m, k, l int, a, b blas64.General, alpha, beta []float64) (zeroR, d1, d2 blas64.General) { 1240 // [ 0 R ] 1241 zeroR = zeros(k+l, n, n) 1242 dst := zeroR 1243 dst.Rows = min(m, k+l) 1244 dst.Cols = k + l 1245 dst.Data = zeroR.Data[n-k-l:] 1246 src := a 1247 src.Rows = min(m, k+l) 1248 src.Cols = k + l 1249 src.Data = a.Data[n-k-l:] 1250 copyGeneral(dst, src) 1251 if m < k+l { 1252 // [ 0 R ] 1253 dst.Rows = k + l - m 1254 dst.Cols = k + l - m 1255 dst.Data = zeroR.Data[m*zeroR.Stride+n-(k+l-m):] 1256 src = b 1257 src.Rows = k + l - m 1258 src.Cols = k + l - m 1259 src.Data = b.Data[(m-k)*b.Stride+n+m-k-l:] 1260 copyGeneral(dst, src) 1261 } 1262 1263 // D1 1264 d1 = zeros(m, k+l, k+l) 1265 for i := 0; i < k; i++ { 1266 d1.Data[i*d1.Stride+i] = 1 1267 } 1268 for i := k; i < min(m, k+l); i++ { 1269 d1.Data[i*d1.Stride+i] = alpha[i] 1270 } 1271 1272 // D2 1273 d2 = zeros(p, k+l, k+l) 1274 for i := 0; i < min(l, m-k); i++ { 1275 d2.Data[i*d2.Stride+i+k] = beta[k+i] 1276 } 1277 for i := m - k; i < l; i++ { 1278 d2.Data[i*d2.Stride+i+k] = 1 1279 } 1280 1281 return zeroR, d1, d2 1282 } 1283 1284 func constructGSVPresults(n, p, m, k, l int, a, b blas64.General) (zeroA, zeroB blas64.General) { 1285 zeroA = zeros(m, n, n) 1286 dst := zeroA 1287 dst.Rows = min(m, k+l) 1288 dst.Cols = k + l 1289 dst.Data = zeroA.Data[n-k-l:] 1290 src := a 1291 dst.Rows = min(m, k+l) 1292 src.Cols = k + l 1293 src.Data = a.Data[n-k-l:] 1294 copyGeneral(dst, src) 1295 1296 zeroB = zeros(p, n, n) 1297 dst = zeroB 1298 dst.Rows = l 1299 dst.Cols = l 1300 dst.Data = zeroB.Data[n-l:] 1301 src = b 1302 dst.Rows = l 1303 src.Cols = l 1304 src.Data = b.Data[n-l:] 1305 copyGeneral(dst, src) 1306 1307 return zeroA, zeroB 1308 } 1309 1310 // distFromIdentity returns the L-infinity distance of an n×n matrix A from the 1311 // identity. If A contains NaN elements, distFromIdentity will return +inf. 1312 func distFromIdentity(n int, a []float64, lda int) float64 { 1313 var dist float64 1314 for i := 0; i < n; i++ { 1315 for j := 0; j < n; j++ { 1316 aij := a[i*lda+j] 1317 if math.IsNaN(aij) { 1318 return math.Inf(1) 1319 } 1320 if i == j { 1321 dist = math.Max(dist, math.Abs(aij-1)) 1322 } else { 1323 dist = math.Max(dist, math.Abs(aij)) 1324 } 1325 } 1326 } 1327 return dist 1328 } 1329 1330 func sameFloat64(a, b float64) bool { 1331 return a == b || math.IsNaN(a) && math.IsNaN(b) 1332 } 1333 1334 // sameLowerTri returns whether n×n matrices A and B are same under the diagonal. 1335 func sameLowerTri(n int, a []float64, lda int, b []float64, ldb int) bool { 1336 for i := 1; i < n; i++ { 1337 for j := 0; j < i; j++ { 1338 aij := a[i*lda+j] 1339 bij := b[i*ldb+j] 1340 if !sameFloat64(aij, bij) { 1341 return false 1342 } 1343 } 1344 } 1345 return true 1346 } 1347 1348 // sameUpperTri returns whether n×n matrices A and B are same above the diagonal. 1349 func sameUpperTri(n int, a []float64, lda int, b []float64, ldb int) bool { 1350 for i := 0; i < n-1; i++ { 1351 for j := i + 1; j < n; j++ { 1352 aij := a[i*lda+j] 1353 bij := b[i*ldb+j] 1354 if !sameFloat64(aij, bij) { 1355 return false 1356 } 1357 } 1358 } 1359 return true 1360 } 1361 1362 // svdJobString returns a string representation of job. 1363 func svdJobString(job lapack.SVDJob) string { 1364 switch job { 1365 case lapack.SVDAll: 1366 return "All" 1367 case lapack.SVDStore: 1368 return "Store" 1369 case lapack.SVDOverwrite: 1370 return "Overwrite" 1371 case lapack.SVDNone: 1372 return "None" 1373 } 1374 return "unknown SVD job" 1375 } 1376 1377 // residualOrthogonal returns the residual 1378 // |I - Q * Qᵀ| if m < n or (m == n and rowwise == true), 1379 // |I - Qᵀ * Q| otherwise. 1380 // It can be used to check that the matrix Q is orthogonal. 1381 func residualOrthogonal(q blas64.General, rowwise bool) float64 { 1382 m, n := q.Rows, q.Cols 1383 if m == 0 || n == 0 { 1384 return 0 1385 } 1386 var transq blas.Transpose 1387 if m < n || (m == n && rowwise) { 1388 transq = blas.NoTrans 1389 } else { 1390 transq = blas.Trans 1391 } 1392 minmn := min(m, n) 1393 1394 // Set work = I. 1395 work := blas64.Symmetric{ 1396 Uplo: blas.Upper, 1397 N: minmn, 1398 Data: make([]float64, minmn*minmn), 1399 Stride: minmn, 1400 } 1401 for i := 0; i < minmn; i++ { 1402 work.Data[i*work.Stride+i] = 1 1403 } 1404 1405 // Compute 1406 // work = work - Q * Qᵀ = I - Q * Qᵀ 1407 // or 1408 // work = work - Qᵀ * Q = I - Qᵀ * Q 1409 blas64.Syrk(transq, -1, q, 1, work) 1410 return dlansy(lapack.MaxColumnSum, blas.Upper, work.N, work.Data, work.Stride) 1411 }