gonum.org/v1/gonum@v0.14.0/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 "golang.org/x/exp/rand" 14 15 "gonum.org/v1/gonum/blas" 16 "gonum.org/v1/gonum/blas/blas64" 17 "gonum.org/v1/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 // 921 //lint:ignore U1000 This is useful for debugging. 922 func printRowise(a []float64, m, n, lda int, beyond bool) { 923 for i := 0; i < m; i++ { 924 end := n 925 if beyond { 926 end = lda 927 } 928 fmt.Println(a[i*lda : i*lda+end]) 929 } 930 } 931 932 func copyGeneral(dst, src blas64.General) { 933 r := min(dst.Rows, src.Rows) 934 c := min(dst.Cols, src.Cols) 935 for i := 0; i < r; i++ { 936 copy(dst.Data[i*dst.Stride:i*dst.Stride+c], src.Data[i*src.Stride:i*src.Stride+c]) 937 } 938 } 939 940 // cloneGeneral allocates and returns an exact copy of the given general matrix. 941 func cloneGeneral(a blas64.General) blas64.General { 942 c := a 943 c.Data = make([]float64, len(a.Data)) 944 copy(c.Data, a.Data) 945 return c 946 } 947 948 // equalGeneral returns whether the general matrices a and b are equal. 949 func equalGeneral(a, b blas64.General) bool { 950 if a.Rows != b.Rows || a.Cols != b.Cols { 951 panic("bad input") 952 } 953 for i := 0; i < a.Rows; i++ { 954 for j := 0; j < a.Cols; j++ { 955 if a.Data[i*a.Stride+j] != b.Data[i*b.Stride+j] { 956 return false 957 } 958 } 959 } 960 return true 961 } 962 963 // equalApproxGeneral returns whether the general matrices a and b are 964 // approximately equal within given tolerance. 965 func equalApproxGeneral(a, b blas64.General, tol float64) bool { 966 if a.Rows != b.Rows || a.Cols != b.Cols { 967 panic("bad input") 968 } 969 for i := 0; i < a.Rows; i++ { 970 for j := 0; j < a.Cols; j++ { 971 diff := a.Data[i*a.Stride+j] - b.Data[i*b.Stride+j] 972 if math.IsNaN(diff) || math.Abs(diff) > tol { 973 return false 974 } 975 } 976 } 977 return true 978 } 979 980 func intsEqual(a, b []int) bool { 981 if len(a) != len(b) { 982 return false 983 } 984 for i, ai := range a { 985 if b[i] != ai { 986 return false 987 } 988 } 989 return true 990 } 991 992 // randSymBand returns an n×n random symmetric positive definite band matrix 993 // with kd diagonals. 994 func randSymBand(uplo blas.Uplo, n, kd, ldab int, rnd *rand.Rand) []float64 { 995 // Allocate a triangular band matrix U or L and fill it with random numbers. 996 var ab []float64 997 if n > 0 { 998 ab = make([]float64, (n-1)*ldab+kd+1) 999 } 1000 for i := range ab { 1001 ab[i] = rnd.NormFloat64() 1002 } 1003 // Make sure that the matrix U or L has a sufficiently positive diagonal. 1004 switch uplo { 1005 case blas.Upper: 1006 for i := 0; i < n; i++ { 1007 ab[i*ldab] = float64(n) + rnd.Float64() 1008 } 1009 case blas.Lower: 1010 for i := 0; i < n; i++ { 1011 ab[i*ldab+kd] = float64(n) + rnd.Float64() 1012 } 1013 } 1014 // Compute Uᵀ*U or L*Lᵀ. The resulting (symmetric) matrix A will be 1015 // positive definite and well-conditioned. 1016 dsbmm(uplo, n, kd, ab, ldab) 1017 return ab 1018 } 1019 1020 // distSymBand returns the max-norm distance between the symmetric band matrices 1021 // A and B. 1022 func distSymBand(uplo blas.Uplo, n, kd int, a []float64, lda int, b []float64, ldb int) float64 { 1023 var dist float64 1024 switch uplo { 1025 case blas.Upper: 1026 for i := 0; i < n; i++ { 1027 for j := 0; j < min(kd+1, n-i); j++ { 1028 dist = math.Max(dist, math.Abs(a[i*lda+j]-b[i*ldb+j])) 1029 } 1030 } 1031 case blas.Lower: 1032 for i := 0; i < n; i++ { 1033 for j := max(0, kd-i); j < kd+1; j++ { 1034 dist = math.Max(dist, math.Abs(a[i*lda+j]-b[i*ldb+j])) 1035 } 1036 } 1037 } 1038 return dist 1039 } 1040 1041 // eye returns an identity matrix of given order and stride. 1042 func eye(n, stride int) blas64.General { 1043 ans := nanGeneral(n, n, stride) 1044 for i := 0; i < n; i++ { 1045 for j := 0; j < n; j++ { 1046 ans.Data[i*ans.Stride+j] = 0 1047 } 1048 ans.Data[i*ans.Stride+i] = 1 1049 } 1050 return ans 1051 } 1052 1053 // zeros returns an m×n matrix with given stride filled with zeros. 1054 func zeros(m, n, stride int) blas64.General { 1055 a := nanGeneral(m, n, stride) 1056 for i := 0; i < m; i++ { 1057 for j := 0; j < n; j++ { 1058 a.Data[i*a.Stride+j] = 0 1059 } 1060 } 1061 return a 1062 } 1063 1064 // extract2x2Block returns the elements of T at [0,0], [0,1], [1,0], and [1,1]. 1065 func extract2x2Block(t []float64, ldt int) (a, b, c, d float64) { 1066 return t[0], t[1], t[ldt], t[ldt+1] 1067 } 1068 1069 // isSchurCanonical returns whether the 2×2 matrix [a b; c d] is in Schur 1070 // canonical form. 1071 func isSchurCanonical(a, b, c, d float64) bool { 1072 return c == 0 || (b != 0 && a == d && math.Signbit(b) != math.Signbit(c)) 1073 } 1074 1075 // isSchurCanonicalGeneral returns whether T is block upper triangular with 1×1 1076 // and 2×2 diagonal blocks, each 2×2 block in Schur canonical form. The function 1077 // checks only along the diagonal and the first subdiagonal, otherwise the lower 1078 // triangle is not accessed. 1079 func isSchurCanonicalGeneral(t blas64.General) bool { 1080 n := t.Cols 1081 if t.Rows != n { 1082 panic("invalid matrix") 1083 } 1084 for j := 0; j < n-1; { 1085 if t.Data[(j+1)*t.Stride+j] == 0 { 1086 // 1×1 block. 1087 for i := j + 1; i < n; i++ { 1088 if t.Data[i*t.Stride+j] != 0 { 1089 return false 1090 } 1091 } 1092 j++ 1093 continue 1094 } 1095 // 2×2 block. 1096 a, b, c, d := extract2x2Block(t.Data[j*t.Stride+j:], t.Stride) 1097 if !isSchurCanonical(a, b, c, d) { 1098 return false 1099 } 1100 for i := j + 2; i < n; i++ { 1101 if t.Data[i*t.Stride+j] != 0 { 1102 return false 1103 } 1104 } 1105 for i := j + 2; i < n; i++ { 1106 if t.Data[i*t.Stride+j+1] != 0 { 1107 return false 1108 } 1109 } 1110 j += 2 1111 } 1112 return true 1113 } 1114 1115 // schurBlockEigenvalues returns the two eigenvalues of the 2×2 matrix [a b; c d] 1116 // that must be in Schur canonical form. 1117 // 1118 //lint:ignore U1000 This is useful for debugging. 1119 func schurBlockEigenvalues(a, b, c, d float64) (ev1, ev2 complex128) { 1120 if !isSchurCanonical(a, b, c, d) { 1121 panic("block not in Schur canonical form") 1122 } 1123 if c == 0 { 1124 return complex(a, 0), complex(d, 0) 1125 } 1126 im := math.Sqrt(math.Abs(b)) * math.Sqrt(math.Abs(c)) 1127 return complex(a, im), complex(a, -im) 1128 } 1129 1130 // schurBlockSize returns the size of the diagonal block at i-th row in the 1131 // upper quasi-triangular matrix t in Schur canonical form, and whether i points 1132 // to the first row of the block. For zero-sized matrices the function returns 0 1133 // and true. 1134 func schurBlockSize(t blas64.General, i int) (size int, first bool) { 1135 if t.Rows != t.Cols { 1136 panic("matrix not square") 1137 } 1138 if t.Rows == 0 { 1139 return 0, true 1140 } 1141 if i < 0 || t.Rows <= i { 1142 panic("index out of range") 1143 } 1144 1145 first = true 1146 if i > 0 && t.Data[i*t.Stride+i-1] != 0 { 1147 // There is a non-zero element to the left, therefore i must 1148 // point to the second row in a 2×2 diagonal block. 1149 first = false 1150 i-- 1151 } 1152 size = 1 1153 if i+1 < t.Rows && t.Data[(i+1)*t.Stride+i] != 0 { 1154 // There is a non-zero element below, this must be a 2×2 1155 // diagonal block. 1156 size = 2 1157 } 1158 return size, first 1159 } 1160 1161 // containsComplex returns whether z is approximately equal to one of the complex 1162 // numbers in v. If z is found, its index in v will be also returned. 1163 func containsComplex(v []complex128, z complex128, tol float64) (found bool, index int) { 1164 for i := range v { 1165 if cmplx.Abs(v[i]-z) < tol { 1166 return true, i 1167 } 1168 } 1169 return false, -1 1170 } 1171 1172 // isAllNaN returns whether x contains only NaN values. 1173 func isAllNaN(x []float64) bool { 1174 for _, v := range x { 1175 if !math.IsNaN(v) { 1176 return false 1177 } 1178 } 1179 return true 1180 } 1181 1182 // isUpperHessenberg returns whether h contains only zeros below the 1183 // subdiagonal. 1184 func isUpperHessenberg(h blas64.General) bool { 1185 if h.Rows != h.Cols { 1186 panic("matrix not square") 1187 } 1188 n := h.Rows 1189 for i := 0; i < n; i++ { 1190 for j := 0; j < n; j++ { 1191 if i > j+1 && h.Data[i*h.Stride+j] != 0 { 1192 return false 1193 } 1194 } 1195 } 1196 return true 1197 } 1198 1199 // isUpperTriangular returns whether a contains only zeros below the diagonal. 1200 func isUpperTriangular(a blas64.General) bool { 1201 n := a.Rows 1202 for i := 1; i < n; i++ { 1203 for j := 0; j < i; j++ { 1204 if a.Data[i*a.Stride+j] != 0 { 1205 return false 1206 } 1207 } 1208 } 1209 return true 1210 } 1211 1212 // unbalancedSparseGeneral returns an m×n dense matrix with a random sparse 1213 // structure consisting of nz nonzero elements. The matrix will be unbalanced by 1214 // multiplying each element randomly by its row or column index. 1215 func unbalancedSparseGeneral(m, n, stride int, nonzeros int, rnd *rand.Rand) blas64.General { 1216 a := zeros(m, n, stride) 1217 for k := 0; k < nonzeros; k++ { 1218 i := rnd.Intn(n) 1219 j := rnd.Intn(n) 1220 if rnd.Float64() < 0.5 { 1221 a.Data[i*stride+j] = float64(i+1) * rnd.NormFloat64() 1222 } else { 1223 a.Data[i*stride+j] = float64(j+1) * rnd.NormFloat64() 1224 } 1225 } 1226 return a 1227 } 1228 1229 // rootsOfUnity returns the n complex numbers whose n-th power is equal to 1. 1230 func rootsOfUnity(n int) []complex128 { 1231 w := make([]complex128, n) 1232 for i := 0; i < n; i++ { 1233 angle := math.Pi * float64(2*i) / float64(n) 1234 w[i] = complex(math.Cos(angle), math.Sin(angle)) 1235 } 1236 return w 1237 } 1238 1239 // constructGSVDresults returns the matrices [ 0 R ], D1 and D2 described 1240 // in the documentation of Dtgsja and Dggsvd3, and the result matrix in 1241 // the documentation for Dggsvp3. 1242 func constructGSVDresults(n, p, m, k, l int, a, b blas64.General, alpha, beta []float64) (zeroR, d1, d2 blas64.General) { 1243 // [ 0 R ] 1244 zeroR = zeros(k+l, n, n) 1245 dst := zeroR 1246 dst.Rows = min(m, k+l) 1247 dst.Cols = k + l 1248 dst.Data = zeroR.Data[n-k-l:] 1249 src := a 1250 src.Rows = min(m, k+l) 1251 src.Cols = k + l 1252 src.Data = a.Data[n-k-l:] 1253 copyGeneral(dst, src) 1254 if m < k+l { 1255 // [ 0 R ] 1256 dst.Rows = k + l - m 1257 dst.Cols = k + l - m 1258 dst.Data = zeroR.Data[m*zeroR.Stride+n-(k+l-m):] 1259 src = b 1260 src.Rows = k + l - m 1261 src.Cols = k + l - m 1262 src.Data = b.Data[(m-k)*b.Stride+n+m-k-l:] 1263 copyGeneral(dst, src) 1264 } 1265 1266 // D1 1267 d1 = zeros(m, k+l, k+l) 1268 for i := 0; i < k; i++ { 1269 d1.Data[i*d1.Stride+i] = 1 1270 } 1271 for i := k; i < min(m, k+l); i++ { 1272 d1.Data[i*d1.Stride+i] = alpha[i] 1273 } 1274 1275 // D2 1276 d2 = zeros(p, k+l, k+l) 1277 for i := 0; i < min(l, m-k); i++ { 1278 d2.Data[i*d2.Stride+i+k] = beta[k+i] 1279 } 1280 for i := m - k; i < l; i++ { 1281 d2.Data[i*d2.Stride+i+k] = 1 1282 } 1283 1284 return zeroR, d1, d2 1285 } 1286 1287 func constructGSVPresults(n, p, m, k, l int, a, b blas64.General) (zeroA, zeroB blas64.General) { 1288 zeroA = zeros(m, n, n) 1289 dst := zeroA 1290 dst.Rows = min(m, k+l) 1291 dst.Cols = k + l 1292 dst.Data = zeroA.Data[n-k-l:] 1293 src := a 1294 dst.Rows = min(m, k+l) 1295 src.Cols = k + l 1296 src.Data = a.Data[n-k-l:] 1297 copyGeneral(dst, src) 1298 1299 zeroB = zeros(p, n, n) 1300 dst = zeroB 1301 dst.Rows = l 1302 dst.Cols = l 1303 dst.Data = zeroB.Data[n-l:] 1304 src = b 1305 dst.Rows = l 1306 src.Cols = l 1307 src.Data = b.Data[n-l:] 1308 copyGeneral(dst, src) 1309 1310 return zeroA, zeroB 1311 } 1312 1313 // distFromIdentity returns the L-infinity distance of an n×n matrix A from the 1314 // identity. If A contains NaN elements, distFromIdentity will return +inf. 1315 func distFromIdentity(n int, a []float64, lda int) float64 { 1316 var dist float64 1317 for i := 0; i < n; i++ { 1318 for j := 0; j < n; j++ { 1319 aij := a[i*lda+j] 1320 if math.IsNaN(aij) { 1321 return math.Inf(1) 1322 } 1323 if i == j { 1324 dist = math.Max(dist, math.Abs(aij-1)) 1325 } else { 1326 dist = math.Max(dist, math.Abs(aij)) 1327 } 1328 } 1329 } 1330 return dist 1331 } 1332 1333 func sameFloat64(a, b float64) bool { 1334 return a == b || math.IsNaN(a) && math.IsNaN(b) 1335 } 1336 1337 // sameLowerTri returns whether n×n matrices A and B are same under the diagonal. 1338 func sameLowerTri(n int, a []float64, lda int, b []float64, ldb int) bool { 1339 for i := 1; i < n; i++ { 1340 for j := 0; j < i; j++ { 1341 aij := a[i*lda+j] 1342 bij := b[i*ldb+j] 1343 if !sameFloat64(aij, bij) { 1344 return false 1345 } 1346 } 1347 } 1348 return true 1349 } 1350 1351 // sameUpperTri returns whether n×n matrices A and B are same above the diagonal. 1352 func sameUpperTri(n int, a []float64, lda int, b []float64, ldb int) bool { 1353 for i := 0; i < n-1; i++ { 1354 for j := i + 1; j < n; j++ { 1355 aij := a[i*lda+j] 1356 bij := b[i*ldb+j] 1357 if !sameFloat64(aij, bij) { 1358 return false 1359 } 1360 } 1361 } 1362 return true 1363 } 1364 1365 // svdJobString returns a string representation of job. 1366 func svdJobString(job lapack.SVDJob) string { 1367 switch job { 1368 case lapack.SVDAll: 1369 return "All" 1370 case lapack.SVDStore: 1371 return "Store" 1372 case lapack.SVDOverwrite: 1373 return "Overwrite" 1374 case lapack.SVDNone: 1375 return "None" 1376 } 1377 return "unknown SVD job" 1378 } 1379 1380 // residualOrthogonal returns the residual 1381 // 1382 // |I - Q * Qᵀ| if m < n or (m == n and rowwise == true), 1383 // |I - Qᵀ * Q| otherwise. 1384 // 1385 // It can be used to check that the matrix Q is orthogonal. 1386 func residualOrthogonal(q blas64.General, rowwise bool) float64 { 1387 m, n := q.Rows, q.Cols 1388 if m == 0 || n == 0 { 1389 return 0 1390 } 1391 var transq blas.Transpose 1392 if m < n || (m == n && rowwise) { 1393 transq = blas.NoTrans 1394 } else { 1395 transq = blas.Trans 1396 } 1397 minmn := min(m, n) 1398 1399 // Set work = I. 1400 work := blas64.Symmetric{ 1401 Uplo: blas.Upper, 1402 N: minmn, 1403 Data: make([]float64, minmn*minmn), 1404 Stride: minmn, 1405 } 1406 for i := 0; i < minmn; i++ { 1407 work.Data[i*work.Stride+i] = 1 1408 } 1409 1410 // Compute 1411 // work = work - Q * Qᵀ = I - Q * Qᵀ 1412 // or 1413 // work = work - Qᵀ * Q = I - Qᵀ * Q 1414 blas64.Syrk(transq, -1, q, 1, work) 1415 return dlansy(lapack.MaxColumnSum, blas.Upper, work.N, work.Data, work.Stride) 1416 }