github.com/jingcheng-WU/gonum@v0.9.1-0.20210323123734-f1a2a11a8f7b/lapack/testlapack/matgen.go (about) 1 // Copyright ©2017 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 "github.com/jingcheng-WU/gonum/blas" 13 "github.com/jingcheng-WU/gonum/blas/blas64" 14 "github.com/jingcheng-WU/gonum/floats" 15 ) 16 17 // Dlatm1 computes the entries of dst as specified by mode, cond and rsign. 18 // 19 // mode describes how dst will be computed: 20 // |mode| == 1: dst[0] = 1 and dst[1:n] = 1/cond 21 // |mode| == 2: dst[:n-1] = 1/cond and dst[n-1] = 1 22 // |mode| == 3: dst[i] = cond^{-i/(n-1)}, i=0,...,n-1 23 // |mode| == 4: dst[i] = 1 - i*(1-1/cond)/(n-1) 24 // |mode| == 5: dst[i] = random number in the range (1/cond, 1) such that 25 // their logarithms are uniformly distributed 26 // |mode| == 6: dst[i] = random number from the distribution given by dist 27 // If mode is negative, the order of the elements of dst will be reversed. 28 // For other values of mode Dlatm1 will panic. 29 // 30 // If rsign is true and mode is not ±6, each entry of dst will be multiplied by 1 31 // or -1 with probability 0.5 32 // 33 // dist specifies the type of distribution to be used when mode == ±6: 34 // dist == 1: Uniform[0,1) 35 // dist == 2: Uniform[-1,1) 36 // dist == 3: Normal(0,1) 37 // For other values of dist Dlatm1 will panic. 38 // 39 // rnd is used as a source of random numbers. 40 func Dlatm1(dst []float64, mode int, cond float64, rsign bool, dist int, rnd *rand.Rand) { 41 amode := mode 42 if amode < 0 { 43 amode = -amode 44 } 45 if amode < 1 || 6 < amode { 46 panic("testlapack: invalid mode") 47 } 48 if cond < 1 { 49 panic("testlapack: cond < 1") 50 } 51 if amode == 6 && (dist < 1 || 3 < dist) { 52 panic("testlapack: invalid dist") 53 } 54 55 n := len(dst) 56 if n == 0 { 57 return 58 } 59 60 switch amode { 61 case 1: 62 dst[0] = 1 63 for i := 1; i < n; i++ { 64 dst[i] = 1 / cond 65 } 66 case 2: 67 for i := 0; i < n-1; i++ { 68 dst[i] = 1 69 } 70 dst[n-1] = 1 / cond 71 case 3: 72 dst[0] = 1 73 if n > 1 { 74 alpha := math.Pow(cond, -1/float64(n-1)) 75 for i := 1; i < n; i++ { 76 dst[i] = math.Pow(alpha, float64(i)) 77 } 78 } 79 case 4: 80 dst[0] = 1 81 if n > 1 { 82 condInv := 1 / cond 83 alpha := (1 - condInv) / float64(n-1) 84 for i := 1; i < n; i++ { 85 dst[i] = float64(n-i-1)*alpha + condInv 86 } 87 } 88 case 5: 89 alpha := math.Log(1 / cond) 90 for i := range dst { 91 dst[i] = math.Exp(alpha * rnd.Float64()) 92 } 93 case 6: 94 switch dist { 95 case 1: 96 for i := range dst { 97 dst[i] = rnd.Float64() 98 } 99 case 2: 100 for i := range dst { 101 dst[i] = 2*rnd.Float64() - 1 102 } 103 case 3: 104 for i := range dst { 105 dst[i] = rnd.NormFloat64() 106 } 107 } 108 } 109 110 if rsign && amode != 6 { 111 for i, v := range dst { 112 if rnd.Float64() < 0.5 { 113 dst[i] = -v 114 } 115 } 116 } 117 118 if mode < 0 { 119 for i := 0; i < n/2; i++ { 120 dst[i], dst[n-i-1] = dst[n-i-1], dst[i] 121 } 122 } 123 } 124 125 // Dlagsy generates an n×n symmetric matrix A, by pre- and post- multiplying a 126 // real diagonal matrix D with a random orthogonal matrix: 127 // A = U * D * Uᵀ. 128 // 129 // work must have length at least 2*n, otherwise Dlagsy will panic. 130 // 131 // The parameter k is unused but it must satisfy 132 // 0 <= k <= n-1. 133 func Dlagsy(n, k int, d []float64, a []float64, lda int, rnd *rand.Rand, work []float64) { 134 checkMatrix(n, n, a, lda) 135 if k < 0 || max(0, n-1) < k { 136 panic("testlapack: invalid value of k") 137 } 138 if len(d) != n { 139 panic("testlapack: bad length of d") 140 } 141 if len(work) < 2*n { 142 panic("testlapack: insufficient work length") 143 } 144 145 // Initialize lower triangle of A to diagonal matrix. 146 for i := 1; i < n; i++ { 147 for j := 0; j < i; j++ { 148 a[i*lda+j] = 0 149 } 150 } 151 for i := 0; i < n; i++ { 152 a[i*lda+i] = d[i] 153 } 154 155 bi := blas64.Implementation() 156 157 // Generate lower triangle of symmetric matrix. 158 for i := n - 2; i >= 0; i-- { 159 for j := 0; j < n-i; j++ { 160 work[j] = rnd.NormFloat64() 161 } 162 wn := bi.Dnrm2(n-i, work[:n-i], 1) 163 wa := math.Copysign(wn, work[0]) 164 var tau float64 165 if wn != 0 { 166 wb := work[0] + wa 167 bi.Dscal(n-i-1, 1/wb, work[1:n-i], 1) 168 work[0] = 1 169 tau = wb / wa 170 } 171 172 // Apply random reflection to A[i:n,i:n] from the left and the 173 // right. 174 // 175 // Compute y := tau * A * u. 176 bi.Dsymv(blas.Lower, n-i, tau, a[i*lda+i:], lda, work[:n-i], 1, 0, work[n:2*n-i], 1) 177 178 // Compute v := y - 1/2 * tau * ( y, u ) * u. 179 alpha := -0.5 * tau * bi.Ddot(n-i, work[n:2*n-i], 1, work[:n-i], 1) 180 bi.Daxpy(n-i, alpha, work[:n-i], 1, work[n:2*n-i], 1) 181 182 // Apply the transformation as a rank-2 update to A[i:n,i:n]. 183 bi.Dsyr2(blas.Lower, n-i, -1, work[:n-i], 1, work[n:2*n-i], 1, a[i*lda+i:], lda) 184 } 185 186 // Store full symmetric matrix. 187 for i := 1; i < n; i++ { 188 for j := 0; j < i; j++ { 189 a[j*lda+i] = a[i*lda+j] 190 } 191 } 192 } 193 194 // Dlagge generates a real general m×n matrix A, by pre- and post-multiplying 195 // a real diagonal matrix D with random orthogonal matrices: 196 // A = U*D*V. 197 // 198 // d must have length min(m,n), and work must have length m+n, otherwise Dlagge 199 // will panic. 200 // 201 // The parameters ku and kl are unused but they must satisfy 202 // 0 <= kl <= m-1, 203 // 0 <= ku <= n-1. 204 func Dlagge(m, n, kl, ku int, d []float64, a []float64, lda int, rnd *rand.Rand, work []float64) { 205 checkMatrix(m, n, a, lda) 206 if kl < 0 || max(0, m-1) < kl { 207 panic("testlapack: invalid value of kl") 208 } 209 if ku < 0 || max(0, n-1) < ku { 210 panic("testlapack: invalid value of ku") 211 } 212 if len(d) != min(m, n) { 213 panic("testlapack: bad length of d") 214 } 215 if len(work) < m+n { 216 panic("testlapack: insufficient work length") 217 } 218 219 // Initialize A to diagonal matrix. 220 for i := 0; i < m; i++ { 221 for j := 0; j < n; j++ { 222 a[i*lda+j] = 0 223 } 224 } 225 for i := 0; i < min(m, n); i++ { 226 a[i*lda+i] = d[i] 227 } 228 229 // Quick exit if the user wants a diagonal matrix. 230 // if kl == 0 && ku == 0 { 231 // return 232 // } 233 234 bi := blas64.Implementation() 235 236 // Pre- and post-multiply A by random orthogonal matrices. 237 for i := min(m, n) - 1; i >= 0; i-- { 238 if i < m-1 { 239 for j := 0; j < m-i; j++ { 240 work[j] = rnd.NormFloat64() 241 } 242 wn := bi.Dnrm2(m-i, work[:m-i], 1) 243 wa := math.Copysign(wn, work[0]) 244 var tau float64 245 if wn != 0 { 246 wb := work[0] + wa 247 bi.Dscal(m-i-1, 1/wb, work[1:m-i], 1) 248 work[0] = 1 249 tau = wb / wa 250 } 251 252 // Multiply A[i:m,i:n] by random reflection from the left. 253 bi.Dgemv(blas.Trans, m-i, n-i, 254 1, a[i*lda+i:], lda, work[:m-i], 1, 255 0, work[m:m+n-i], 1) 256 bi.Dger(m-i, n-i, 257 -tau, work[:m-i], 1, work[m:m+n-i], 1, 258 a[i*lda+i:], lda) 259 } 260 if i < n-1 { 261 for j := 0; j < n-i; j++ { 262 work[j] = rnd.NormFloat64() 263 } 264 wn := bi.Dnrm2(n-i, work[:n-i], 1) 265 wa := math.Copysign(wn, work[0]) 266 var tau float64 267 if wn != 0 { 268 wb := work[0] + wa 269 bi.Dscal(n-i-1, 1/wb, work[1:n-i], 1) 270 work[0] = 1 271 tau = wb / wa 272 } 273 274 // Multiply A[i:m,i:n] by random reflection from the right. 275 bi.Dgemv(blas.NoTrans, m-i, n-i, 276 1, a[i*lda+i:], lda, work[:n-i], 1, 277 0, work[n:n+m-i], 1) 278 bi.Dger(m-i, n-i, 279 -tau, work[n:n+m-i], 1, work[:n-i], 1, 280 a[i*lda+i:], lda) 281 } 282 } 283 284 // TODO(vladimir-ch): Reduce number of subdiagonals to kl and number of 285 // superdiagonals to ku. 286 } 287 288 // dlarnv fills dst with random numbers from a uniform or normal distribution 289 // specified by dist: 290 // dist=1: uniform(0,1), 291 // dist=2: uniform(-1,1), 292 // dist=3: normal(0,1). 293 // For other values of dist dlarnv will panic. 294 func dlarnv(dst []float64, dist int, rnd *rand.Rand) { 295 switch dist { 296 default: 297 panic("testlapack: invalid dist") 298 case 1: 299 for i := range dst { 300 dst[i] = rnd.Float64() 301 } 302 case 2: 303 for i := range dst { 304 dst[i] = 2*rnd.Float64() - 1 305 } 306 case 3: 307 for i := range dst { 308 dst[i] = rnd.NormFloat64() 309 } 310 } 311 } 312 313 // dlattr generates an n×n triangular test matrix A with its properties uniquely 314 // determined by imat and uplo, and returns whether A has unit diagonal. If diag 315 // is blas.Unit, the diagonal elements are set so that A[k,k]=k. 316 // 317 // trans specifies whether the matrix A or its transpose will be used. 318 // 319 // If imat is greater than 10, dlattr also generates the right hand side of the 320 // linear system A*x=b, or Aᵀ*x=b. Valid values of imat are 7, and all between 11 321 // and 19, inclusive. 322 // 323 // b mush have length n, and work must have length 3*n, and dlattr will panic 324 // otherwise. 325 func dlattr(imat int, uplo blas.Uplo, trans blas.Transpose, n int, a []float64, lda int, b, work []float64, rnd *rand.Rand) (diag blas.Diag) { 326 checkMatrix(n, n, a, lda) 327 if len(b) != n { 328 panic("testlapack: bad length of b") 329 } 330 if len(work) < 3*n { 331 panic("testlapack: insufficient length of work") 332 } 333 if uplo != blas.Upper && uplo != blas.Lower { 334 panic("testlapack: bad uplo") 335 } 336 if trans != blas.Trans && trans != blas.NoTrans { 337 panic("testlapack: bad trans") 338 } 339 340 if n == 0 { 341 return blas.NonUnit 342 } 343 344 ulp := dlamchE * dlamchB 345 smlnum := dlamchS 346 bignum := (1 - ulp) / smlnum 347 348 bi := blas64.Implementation() 349 350 switch imat { 351 default: 352 // TODO(vladimir-ch): Implement the remaining cases. 353 panic("testlapack: invalid or unimplemented imat") 354 case 7: 355 // Identity matrix. The diagonal is set to NaN. 356 diag = blas.Unit 357 switch uplo { 358 case blas.Upper: 359 for i := 0; i < n; i++ { 360 a[i*lda+i] = math.NaN() 361 for j := i + 1; j < n; j++ { 362 a[i*lda+j] = 0 363 } 364 } 365 case blas.Lower: 366 for i := 0; i < n; i++ { 367 for j := 0; j < i; j++ { 368 a[i*lda+j] = 0 369 } 370 a[i*lda+i] = math.NaN() 371 } 372 } 373 case 11: 374 // Generate a triangular matrix with elements between -1 and 1, 375 // give the diagonal norm 2 to make it well-conditioned, and 376 // make the right hand side large so that it requires scaling. 377 diag = blas.NonUnit 378 switch uplo { 379 case blas.Upper: 380 for i := 0; i < n-1; i++ { 381 dlarnv(a[i*lda+i:i*lda+n], 2, rnd) 382 } 383 case blas.Lower: 384 for i := 1; i < n; i++ { 385 dlarnv(a[i*lda:i*lda+i+1], 2, rnd) 386 } 387 } 388 for i := 0; i < n; i++ { 389 a[i*lda+i] = math.Copysign(2, a[i*lda+i]) 390 } 391 // Set the right hand side so that the largest value is bignum. 392 dlarnv(b, 2, rnd) 393 imax := bi.Idamax(n, b, 1) 394 bscal := bignum / math.Max(1, b[imax]) 395 bi.Dscal(n, bscal, b, 1) 396 case 12: 397 // Make the first diagonal element in the solve small to cause 398 // immediate overflow when dividing by T[j,j]. The off-diagonal 399 // elements are small (cnorm[j] < 1). 400 diag = blas.NonUnit 401 tscal := 1 / math.Max(1, float64(n-1)) 402 switch uplo { 403 case blas.Upper: 404 for i := 0; i < n; i++ { 405 dlarnv(a[i*lda+i:i*lda+n], 2, rnd) 406 bi.Dscal(n-i-1, tscal, a[i*lda+i+1:], 1) 407 a[i*lda+i] = math.Copysign(1, a[i*lda+i]) 408 } 409 a[(n-1)*lda+n-1] *= smlnum 410 case blas.Lower: 411 for i := 0; i < n; i++ { 412 dlarnv(a[i*lda:i*lda+i+1], 2, rnd) 413 bi.Dscal(i, tscal, a[i*lda:], 1) 414 a[i*lda+i] = math.Copysign(1, a[i*lda+i]) 415 } 416 a[0] *= smlnum 417 } 418 dlarnv(b, 2, rnd) 419 case 13: 420 // Make the first diagonal element in the solve small to cause 421 // immediate overflow when dividing by T[j,j]. The off-diagonal 422 // elements are O(1) (cnorm[j] > 1). 423 diag = blas.NonUnit 424 switch uplo { 425 case blas.Upper: 426 for i := 0; i < n; i++ { 427 dlarnv(a[i*lda+i:i*lda+n], 2, rnd) 428 a[i*lda+i] = math.Copysign(1, a[i*lda+i]) 429 } 430 a[(n-1)*lda+n-1] *= smlnum 431 case blas.Lower: 432 for i := 0; i < n; i++ { 433 dlarnv(a[i*lda:i*lda+i+1], 2, rnd) 434 a[i*lda+i] = math.Copysign(1, a[i*lda+i]) 435 } 436 a[0] *= smlnum 437 } 438 dlarnv(b, 2, rnd) 439 case 14: 440 // T is diagonal with small numbers on the diagonal to 441 // make the growth factor underflow, but a small right hand side 442 // chosen so that the solution does not overflow. 443 diag = blas.NonUnit 444 switch uplo { 445 case blas.Upper: 446 for i := 0; i < n; i++ { 447 for j := i + 1; j < n; j++ { 448 a[i*lda+j] = 0 449 } 450 if (n-1-i)&0x2 == 0 { 451 a[i*lda+i] = smlnum 452 } else { 453 a[i*lda+i] = 1 454 } 455 } 456 case blas.Lower: 457 for i := 0; i < n; i++ { 458 for j := 0; j < i; j++ { 459 a[i*lda+j] = 0 460 } 461 if i&0x2 == 0 { 462 a[i*lda+i] = smlnum 463 } else { 464 a[i*lda+i] = 1 465 } 466 } 467 } 468 // Set the right hand side alternately zero and small. 469 switch uplo { 470 case blas.Upper: 471 b[0] = 0 472 for i := n - 1; i > 0; i -= 2 { 473 b[i] = 0 474 b[i-1] = smlnum 475 } 476 case blas.Lower: 477 for i := 0; i < n-1; i += 2 { 478 b[i] = 0 479 b[i+1] = smlnum 480 } 481 b[n-1] = 0 482 } 483 case 15: 484 // Make the diagonal elements small to cause gradual overflow 485 // when dividing by T[j,j]. To control the amount of scaling 486 // needed, the matrix is bidiagonal. 487 diag = blas.NonUnit 488 texp := 1 / math.Max(1, float64(n-1)) 489 tscal := math.Pow(smlnum, texp) 490 switch uplo { 491 case blas.Upper: 492 for i := 0; i < n; i++ { 493 a[i*lda+i] = tscal 494 if i < n-1 { 495 a[i*lda+i+1] = -1 496 } 497 for j := i + 2; j < n; j++ { 498 a[i*lda+j] = 0 499 } 500 } 501 case blas.Lower: 502 for i := 0; i < n; i++ { 503 for j := 0; j < i-1; j++ { 504 a[i*lda+j] = 0 505 } 506 if i > 0 { 507 a[i*lda+i-1] = -1 508 } 509 a[i*lda+i] = tscal 510 } 511 } 512 dlarnv(b, 2, rnd) 513 case 16: 514 // One zero diagonal element. 515 diag = blas.NonUnit 516 switch uplo { 517 case blas.Upper: 518 for i := 0; i < n; i++ { 519 dlarnv(a[i*lda+i:i*lda+n], 2, rnd) 520 a[i*lda+i] = math.Copysign(2, a[i*lda+i]) 521 } 522 case blas.Lower: 523 for i := 0; i < n; i++ { 524 dlarnv(a[i*lda:i*lda+i+1], 2, rnd) 525 a[i*lda+i] = math.Copysign(2, a[i*lda+i]) 526 } 527 } 528 iy := n / 2 529 a[iy*lda+iy] = 0 530 dlarnv(b, 2, rnd) 531 bi.Dscal(n, 2, b, 1) 532 case 17: 533 // Make the offdiagonal elements large to cause overflow when 534 // adding a column of T. In the non-transposed case, the matrix 535 // is constructed to cause overflow when adding a column in 536 // every other step. 537 diag = blas.NonUnit 538 tscal := (1 - ulp) / (dlamchS / ulp) 539 texp := 1.0 540 switch uplo { 541 case blas.Upper: 542 for i := 0; i < n; i++ { 543 for j := i; j < n; j++ { 544 a[i*lda+j] = 0 545 } 546 } 547 for j := n - 1; j >= 1; j -= 2 { 548 a[j] = -tscal / float64(n+1) 549 a[j*lda+j] = 1 550 b[j] = texp * (1 - ulp) 551 a[j-1] = -tscal / float64(n+1) / float64(n+2) 552 a[(j-1)*lda+j-1] = 1 553 b[j-1] = texp * float64(n*n+n-1) 554 texp *= 2 555 } 556 b[0] = float64(n+1) / float64(n+2) * tscal 557 case blas.Lower: 558 for i := 0; i < n; i++ { 559 for j := 0; j <= i; j++ { 560 a[i*lda+j] = 0 561 } 562 } 563 for j := 0; j < n-1; j += 2 { 564 a[(n-1)*lda+j] = -tscal / float64(n+1) 565 a[j*lda+j] = 1 566 b[j] = texp * (1 - ulp) 567 a[(n-1)*lda+j+1] = -tscal / float64(n+1) / float64(n+2) 568 a[(j+1)*lda+j+1] = 1 569 b[j+1] = texp * float64(n*n+n-1) 570 texp *= 2 571 } 572 b[n-1] = float64(n+1) / float64(n+2) * tscal 573 } 574 case 18: 575 // Generate a unit triangular matrix with elements between -1 576 // and 1, and make the right hand side large so that it requires 577 // scaling. The diagonal is set to NaN. 578 diag = blas.Unit 579 switch uplo { 580 case blas.Upper: 581 for i := 0; i < n; i++ { 582 a[i*lda+i] = math.NaN() 583 dlarnv(a[i*lda+i+1:i*lda+n], 2, rnd) 584 } 585 case blas.Lower: 586 for i := 0; i < n; i++ { 587 dlarnv(a[i*lda:i*lda+i], 2, rnd) 588 a[i*lda+i] = math.NaN() 589 } 590 } 591 // Set the right hand side so that the largest value is bignum. 592 dlarnv(b, 2, rnd) 593 iy := bi.Idamax(n, b, 1) 594 bnorm := math.Abs(b[iy]) 595 bscal := bignum / math.Max(1, bnorm) 596 bi.Dscal(n, bscal, b, 1) 597 case 19: 598 // Generate a triangular matrix with elements between 599 // bignum/(n-1) and bignum so that at least one of the column 600 // norms will exceed bignum. 601 // Dlatrs cannot handle this case for (typically) n>5. 602 diag = blas.NonUnit 603 tleft := bignum / math.Max(1, float64(n-1)) 604 tscal := bignum * (float64(n-1) / math.Max(1, float64(n))) 605 switch uplo { 606 case blas.Upper: 607 for i := 0; i < n; i++ { 608 dlarnv(a[i*lda+i:i*lda+n], 2, rnd) 609 for j := i; j < n; j++ { 610 aij := a[i*lda+j] 611 a[i*lda+j] = math.Copysign(tleft, aij) + tscal*aij 612 } 613 } 614 case blas.Lower: 615 for i := 0; i < n; i++ { 616 dlarnv(a[i*lda:i*lda+i+1], 2, rnd) 617 for j := 0; j <= i; j++ { 618 aij := a[i*lda+j] 619 a[i*lda+j] = math.Copysign(tleft, aij) + tscal*aij 620 } 621 } 622 } 623 dlarnv(b, 2, rnd) 624 bi.Dscal(n, 2, b, 1) 625 } 626 627 // Flip the matrix if the transpose will be used. 628 if trans == blas.Trans { 629 switch uplo { 630 case blas.Upper: 631 for j := 0; j < n/2; j++ { 632 bi.Dswap(n-2*j-1, a[j*lda+j:], 1, a[(j+1)*lda+n-j-1:], -lda) 633 } 634 case blas.Lower: 635 for j := 0; j < n/2; j++ { 636 bi.Dswap(n-2*j-1, a[j*lda+j:], lda, a[(n-j-1)*lda+j+1:], -1) 637 } 638 } 639 } 640 641 return diag 642 } 643 644 func checkMatrix(m, n int, a []float64, lda int) { 645 if m < 0 { 646 panic("testlapack: m < 0") 647 } 648 if n < 0 { 649 panic("testlapack: n < 0") 650 } 651 if lda < max(1, n) { 652 panic("testlapack: lda < max(1, n)") 653 } 654 if len(a) < (m-1)*lda+n { 655 panic("testlapack: insufficient matrix slice length") 656 } 657 } 658 659 // randomOrthogonal returns an n×n random orthogonal matrix. 660 func randomOrthogonal(n int, rnd *rand.Rand) blas64.General { 661 q := eye(n, n) 662 x := make([]float64, n) 663 v := make([]float64, n) 664 for j := 0; j < n-1; j++ { 665 // x represents the j-th column of a random matrix. 666 for i := 0; i < j; i++ { 667 x[i] = 0 668 } 669 for i := j; i < n; i++ { 670 x[i] = rnd.NormFloat64() 671 } 672 // Compute v that represents the elementary reflector that 673 // annihilates the subdiagonal elements of x. 674 reflector(v, x, j) 675 // Compute Q * H_j and store the result into Q. 676 applyReflector(q, q, v) 677 } 678 return q 679 } 680 681 // reflector generates a Householder reflector v that zeros out subdiagonal 682 // entries in the j-th column of a matrix. 683 func reflector(v, col []float64, j int) { 684 n := len(col) 685 if len(v) != n { 686 panic("slice length mismatch") 687 } 688 if j < 0 || n <= j { 689 panic("invalid column index") 690 } 691 692 for i := range v { 693 v[i] = 0 694 } 695 if j == n-1 { 696 return 697 } 698 s := floats.Norm(col[j:], 2) 699 if s == 0 { 700 return 701 } 702 v[j] = col[j] + math.Copysign(s, col[j]) 703 copy(v[j+1:], col[j+1:]) 704 s = floats.Norm(v[j:], 2) 705 floats.Scale(1/s, v[j:]) 706 } 707 708 // applyReflector computes Q*H where H is a Householder matrix represented by 709 // the Householder reflector v. 710 func applyReflector(qh blas64.General, q blas64.General, v []float64) { 711 n := len(v) 712 if qh.Rows != n || qh.Cols != n { 713 panic("bad size of qh") 714 } 715 if q.Rows != n || q.Cols != n { 716 panic("bad size of q") 717 } 718 qv := make([]float64, n) 719 blas64.Gemv(blas.NoTrans, 1, q, blas64.Vector{Data: v, Inc: 1}, 0, blas64.Vector{Data: qv, Inc: 1}) 720 for i := 0; i < n; i++ { 721 for j := 0; j < n; j++ { 722 qh.Data[i*qh.Stride+j] = q.Data[i*q.Stride+j] 723 } 724 } 725 for i := 0; i < n; i++ { 726 for j := 0; j < n; j++ { 727 qh.Data[i*qh.Stride+j] -= 2 * qv[i] * v[j] 728 } 729 } 730 var norm2 float64 731 for _, vi := range v { 732 norm2 += vi * vi 733 } 734 norm2inv := 1 / norm2 735 for i := 0; i < n; i++ { 736 for j := 0; j < n; j++ { 737 qh.Data[i*qh.Stride+j] *= norm2inv 738 } 739 } 740 } 741 742 func dlattb(kind int, uplo blas.Uplo, trans blas.Transpose, n, kd int, ab []float64, ldab int, rnd *rand.Rand) (diag blas.Diag, b []float64) { 743 switch { 744 case kind < 1 || 18 < kind: 745 panic("bad matrix kind") 746 case (6 <= kind && kind <= 9) || kind == 17: 747 diag = blas.Unit 748 default: 749 diag = blas.NonUnit 750 } 751 752 if n == 0 { 753 return 754 } 755 756 const ( 757 unfl = dlamchS 758 ulp = dlamchE * dlamchB 759 smlnum = unfl 760 bignum = (1 - ulp) / smlnum 761 762 eps = dlamchP 763 small = 0.25 * (dlamchS / eps) 764 large = 1 / small 765 badc2 = 0.1 / eps 766 ) 767 badc1 := math.Sqrt(badc2) 768 769 var cndnum float64 770 switch { 771 case kind == 2 || kind == 8: 772 cndnum = badc1 773 case kind == 3 || kind == 9: 774 cndnum = badc2 775 default: 776 cndnum = 2 777 } 778 779 uniformM11 := func() float64 { 780 return 2*rnd.Float64() - 1 781 } 782 783 // Allocate the right-hand side and fill it with random numbers. 784 // The pathological matrix types below overwrite it with their 785 // custom vector. 786 b = make([]float64, n) 787 for i := range b { 788 b[i] = uniformM11() 789 } 790 791 bi := blas64.Implementation() 792 switch kind { 793 default: 794 panic("test matrix type not implemented") 795 796 case 1, 2, 3, 4, 5: 797 // Non-unit triangular matrix 798 // TODO(vladimir-ch) 799 var kl, ku int 800 switch uplo { 801 case blas.Upper: 802 ku = kd 803 kl = 0 804 // IOFF = 1 + MAX( 0, KD-N+1 ) 805 // PACKIT = 'Q' 806 // 'Q' => store the upper triangle in band storage scheme 807 // (only if matrix symmetric or upper triangular) 808 case blas.Lower: 809 ku = 0 810 kl = kd 811 // IOFF = 1 812 // PACKIT = 'B' 813 // 'B' => store the lower triangle in band storage scheme 814 // (only if matrix symmetric or lower triangular) 815 } 816 anorm := 1.0 817 switch kind { 818 case 4: 819 anorm = small 820 case 5: 821 anorm = large 822 } 823 _, _, _ = kl, ku, anorm 824 // // DIST = 'S' // UNIFORM(-1, 1) 825 // // MODE = 3 // MODE = 3 sets D(I)=CNDNUM**(-(I-1)/(N-1)) 826 // // TYPE = 'N' // If TYPE='N', the generated matrix is nonsymmetric 827 // CALL DLATMS( N, N, DIST, ISEED, TYPE, B, MODE, CNDNUM, ANORM, 828 // $ KL, KU, PACKIT, AB( IOFF, 1 ), LDAB, WORK, INFO ) 829 panic("test matrix type not implemented") 830 831 case 6: 832 // Matrix is the identity. 833 if uplo == blas.Upper { 834 for i := 0; i < n; i++ { 835 // Fill the diagonal with non-unit numbers. 836 ab[i*ldab] = float64(i + 2) 837 for j := 1; j < min(n-i, kd+1); j++ { 838 ab[i*ldab+j] = 0 839 } 840 } 841 } else { 842 for i := 0; i < n; i++ { 843 for j := max(0, kd-i); j < kd; j++ { 844 ab[i*ldab+j] = 0 845 } 846 // Fill the diagonal with non-unit numbers. 847 ab[i*ldab+kd] = float64(i + 2) 848 } 849 } 850 851 case 7, 8, 9: 852 // Non-trivial unit triangular matrix 853 // 854 // A unit triangular matrix T with condition cndnum is formed. 855 // In this version, T only has bandwidth 2, the rest of it is 856 // zero. 857 858 tnorm := math.Sqrt(cndnum) 859 860 // Initialize AB to zero. 861 if uplo == blas.Upper { 862 for i := 0; i < n; i++ { 863 // Fill the diagonal with non-unit numbers. 864 ab[i*ldab] = float64(i + 2) 865 for j := 1; j < min(n-i, kd+1); j++ { 866 ab[i*ldab+j] = 0 867 } 868 } 869 } else { 870 for i := 0; i < n; i++ { 871 for j := max(0, kd-i); j < kd; j++ { 872 ab[i*ldab+j] = 0 873 } 874 // Fill the diagonal with non-unit numbers. 875 ab[i*ldab+kd] = float64(i + 2) 876 } 877 } 878 879 switch kd { 880 case 0: 881 // Unit diagonal matrix, nothing else to do. 882 case 1: 883 // Special case: T is tridiagonal. Set every other 884 // off-diagonal so that the matrix has norm tnorm+1. 885 if n > 1 { 886 if uplo == blas.Upper { 887 ab[1] = math.Copysign(tnorm, uniformM11()) 888 for i := 2; i < n-1; i += 2 { 889 ab[i*ldab+1] = tnorm * uniformM11() 890 } 891 } else { 892 ab[ldab] = math.Copysign(tnorm, uniformM11()) 893 for i := 3; i < n; i += 2 { 894 ab[i*ldab] = tnorm * uniformM11() 895 } 896 } 897 } 898 default: 899 // Form a unit triangular matrix T with condition cndnum. T is given 900 // by 901 // | 1 + * | 902 // | 1 + | 903 // T = | 1 + * | 904 // | 1 + | 905 // | 1 + * | 906 // | 1 + | 907 // | . . . | 908 // Each element marked with a '*' is formed by taking the product of 909 // the adjacent elements marked with '+'. The '*'s can be chosen 910 // freely, and the '+'s are chosen so that the inverse of T will 911 // have elements of the same magnitude as T. 912 work1 := make([]float64, n) 913 work2 := make([]float64, n) 914 star1 := math.Copysign(tnorm, uniformM11()) 915 sfac := math.Sqrt(tnorm) 916 plus1 := math.Copysign(sfac, uniformM11()) 917 for i := 0; i < n; i += 2 { 918 work1[i] = plus1 919 work2[i] = star1 920 if i+1 == n { 921 continue 922 } 923 plus2 := star1 / plus1 924 work1[i+1] = plus2 925 plus1 = star1 / plus2 926 // Generate a new *-value with norm between sqrt(tnorm) 927 // and tnorm. 928 rexp := uniformM11() 929 if rexp < 0 { 930 star1 = -math.Pow(sfac, 1-rexp) 931 } else { 932 star1 = math.Pow(sfac, 1+rexp) 933 } 934 } 935 // Copy the diagonal to AB. 936 if uplo == blas.Upper { 937 bi.Dcopy(n-1, work1, 1, ab[1:], ldab) 938 if n > 2 { 939 bi.Dcopy(n-2, work2, 1, ab[2:], ldab) 940 } 941 } else { 942 bi.Dcopy(n-1, work1, 1, ab[ldab+kd-1:], ldab) 943 if n > 2 { 944 bi.Dcopy(n-2, work2, 1, ab[2*ldab+kd-2:], ldab) 945 } 946 } 947 } 948 949 // Pathological test cases 10-18: these triangular matrices are badly 950 // scaled or badly conditioned, so when used in solving a triangular 951 // system they may cause overflow in the solution vector. 952 953 case 10: 954 // Generate a triangular matrix with elements between -1 and 1. 955 // Give the diagonal norm 2 to make it well-conditioned. 956 // Make the right hand side large so that it requires scaling. 957 if uplo == blas.Upper { 958 for i := 0; i < n; i++ { 959 for j := 0; j < min(n-j, kd+1); j++ { 960 ab[i*ldab+j] = uniformM11() 961 } 962 ab[i*ldab] = math.Copysign(2, ab[i*ldab]) 963 } 964 } else { 965 for i := 0; i < n; i++ { 966 for j := max(0, kd-i); j < kd+1; j++ { 967 ab[i*ldab+j] = uniformM11() 968 } 969 ab[i*ldab+kd] = math.Copysign(2, ab[i*ldab+kd]) 970 } 971 } 972 // Set the right hand side so that the largest value is bignum. 973 bnorm := math.Abs(b[bi.Idamax(n, b, 1)]) 974 bscal := bignum / math.Max(1, bnorm) 975 bi.Dscal(n, bscal, b, 1) 976 977 case 11: 978 // Make the first diagonal element in the solve small to cause 979 // immediate overflow when dividing by T[j,j]. 980 // The offdiagonal elements are small (cnorm[j] < 1). 981 tscal := 1 / float64(kd+1) 982 if uplo == blas.Upper { 983 for i := 0; i < n; i++ { 984 jlen := min(n-i, kd+1) 985 arow := ab[i*ldab : i*ldab+jlen] 986 dlarnv(arow, 2, rnd) 987 if jlen > 1 { 988 bi.Dscal(jlen-1, tscal, arow[1:], 1) 989 } 990 ab[i*ldab] = math.Copysign(1, ab[i*ldab]) 991 } 992 ab[(n-1)*ldab] *= smlnum 993 } else { 994 for i := 0; i < n; i++ { 995 jlen := min(i+1, kd+1) 996 arow := ab[i*ldab+kd+1-jlen : i*ldab+kd+1] 997 dlarnv(arow, 2, rnd) 998 if jlen > 1 { 999 bi.Dscal(jlen-1, tscal, arow[:jlen-1], 1) 1000 } 1001 ab[i*ldab+kd] = math.Copysign(1, ab[i*ldab+kd]) 1002 } 1003 ab[kd] *= smlnum 1004 } 1005 1006 case 12: 1007 // Make the first diagonal element in the solve small to cause 1008 // immediate overflow when dividing by T[j,j]. 1009 // The offdiagonal elements are O(1) (cnorm[j] > 1). 1010 if uplo == blas.Upper { 1011 for i := 0; i < n; i++ { 1012 jlen := min(n-i, kd+1) 1013 arow := ab[i*ldab : i*ldab+jlen] 1014 dlarnv(arow, 2, rnd) 1015 ab[i*ldab] = math.Copysign(1, ab[i*ldab]) 1016 } 1017 ab[(n-1)*ldab] *= smlnum 1018 } else { 1019 for i := 0; i < n; i++ { 1020 jlen := min(i+1, kd+1) 1021 arow := ab[i*ldab+kd+1-jlen : i*ldab+kd+1] 1022 dlarnv(arow, 2, rnd) 1023 ab[i*ldab+kd] = math.Copysign(1, ab[i*ldab+kd]) 1024 } 1025 ab[kd] *= smlnum 1026 } 1027 1028 case 13: 1029 // T is diagonal with small numbers on the diagonal to make the growth 1030 // factor underflow, but a small right hand side chosen so that the 1031 // solution does not overflow. 1032 if uplo == blas.Upper { 1033 icount := 1 1034 for i := n - 1; i >= 0; i-- { 1035 if icount <= 2 { 1036 ab[i*ldab] = smlnum 1037 } else { 1038 ab[i*ldab] = 1 1039 } 1040 for j := 1; j < min(n-i, kd+1); j++ { 1041 ab[i*ldab+j] = 0 1042 } 1043 icount++ 1044 if icount > 4 { 1045 icount = 1 1046 } 1047 } 1048 } else { 1049 icount := 1 1050 for i := 0; i < n; i++ { 1051 for j := max(0, kd-i); j < kd; j++ { 1052 ab[i*ldab+j] = 0 1053 } 1054 if icount <= 2 { 1055 ab[i*ldab+kd] = smlnum 1056 } else { 1057 ab[i*ldab+kd] = 1 1058 } 1059 icount++ 1060 if icount > 4 { 1061 icount = 1 1062 } 1063 } 1064 } 1065 // Set the right hand side alternately zero and small. 1066 if uplo == blas.Upper { 1067 b[0] = 0 1068 for i := n - 1; i > 1; i -= 2 { 1069 b[i] = 0 1070 b[i-1] = smlnum 1071 } 1072 } else { 1073 b[n-1] = 0 1074 for i := 0; i < n-1; i += 2 { 1075 b[i] = 0 1076 b[i+1] = smlnum 1077 } 1078 } 1079 1080 case 14: 1081 // Make the diagonal elements small to cause gradual overflow when 1082 // dividing by T[j,j]. To control the amount of scaling needed, the 1083 // matrix is bidiagonal. 1084 tscal := math.Pow(smlnum, 1/float64(kd+1)) 1085 if uplo == blas.Upper { 1086 for i := 0; i < n; i++ { 1087 ab[i*ldab] = tscal 1088 if i < n-1 && kd > 0 { 1089 ab[i*ldab+1] = -1 1090 } 1091 for j := 2; j < min(n-i, kd+1); j++ { 1092 ab[i*ldab+j] = 0 1093 } 1094 } 1095 b[n-1] = 1 1096 } else { 1097 for i := 0; i < n; i++ { 1098 for j := max(0, kd-i); j < kd-1; j++ { 1099 ab[i*ldab+j] = 0 1100 } 1101 if i > 0 && kd > 0 { 1102 ab[i*ldab+kd-1] = -1 1103 } 1104 ab[i*ldab+kd] = tscal 1105 } 1106 b[0] = 1 1107 } 1108 1109 case 15: 1110 // One zero diagonal element. 1111 iy := n / 2 1112 if uplo == blas.Upper { 1113 for i := 0; i < n; i++ { 1114 jlen := min(n-i, kd+1) 1115 dlarnv(ab[i*ldab:i*ldab+jlen], 2, rnd) 1116 if i != iy { 1117 ab[i*ldab] = math.Copysign(2, ab[i*ldab]) 1118 } else { 1119 ab[i*ldab] = 0 1120 } 1121 } 1122 } else { 1123 for i := 0; i < n; i++ { 1124 jlen := min(i+1, kd+1) 1125 dlarnv(ab[i*ldab+kd+1-jlen:i*ldab+kd+1], 2, rnd) 1126 if i != iy { 1127 ab[i*ldab+kd] = math.Copysign(2, ab[i*ldab+kd]) 1128 } else { 1129 ab[i*ldab+kd] = 0 1130 } 1131 } 1132 } 1133 bi.Dscal(n, 2, b, 1) 1134 1135 // case 16: 1136 // TODO(vladimir-ch) 1137 // Make the off-diagonal elements large to cause overflow when adding a 1138 // column of T. In the non-transposed case, the matrix is constructed to 1139 // cause overflow when adding a column in every other step. 1140 1141 // Initialize the matrix to zero. 1142 // if uplo == blas.Upper { 1143 // for i := 0; i < n; i++ { 1144 // for j := 0; j < min(n-i, kd+1); j++ { 1145 // ab[i*ldab+j] = 0 1146 // } 1147 // } 1148 // } else { 1149 // for i := 0; i < n; i++ { 1150 // for j := max(0, kd-i); j < kd+1; j++ { 1151 // ab[i*ldab+j] = 0 1152 // } 1153 // } 1154 // } 1155 1156 // const tscal = (1 - ulp) / (unfl / ulp) 1157 // texp := 1.0 1158 // if kd > 0 { 1159 // if uplo == blas.Upper { 1160 // for j := n - 1; j >= 0; j -= kd { 1161 // } 1162 // } else { 1163 // for j := 0; j < n; j += kd { 1164 // } 1165 // } 1166 // } else { 1167 // // Diagonal matrix. 1168 // for i := 0; i < n; i++ { 1169 // ab[i*ldab] = 1 1170 // b[i] = float64(i + 1) 1171 // } 1172 // } 1173 1174 case 17: 1175 // Generate a unit triangular matrix with elements between -1 and 1, and 1176 // make the right hand side large so that it requires scaling. 1177 if uplo == blas.Upper { 1178 for i := 0; i < n; i++ { 1179 ab[i*ldab] = float64(i + 2) 1180 jlen := min(n-i-1, kd) 1181 if jlen > 0 { 1182 dlarnv(ab[i*ldab+1:i*ldab+1+jlen], 2, rnd) 1183 } 1184 } 1185 } else { 1186 for i := 0; i < n; i++ { 1187 jlen := min(i, kd) 1188 if jlen > 0 { 1189 dlarnv(ab[i*ldab+kd-jlen:i*ldab+kd], 2, rnd) 1190 } 1191 ab[i*ldab+kd] = float64(i + 2) 1192 } 1193 } 1194 // Set the right hand side so that the largest value is bignum. 1195 bnorm := math.Abs(b[bi.Idamax(n, b, 1)]) 1196 bscal := bignum / math.Max(1, bnorm) 1197 bi.Dscal(n, bscal, b, 1) 1198 1199 case 18: 1200 // Generate a triangular matrix with elements between bignum/kd and 1201 // bignum so that at least one of the column norms will exceed bignum. 1202 tleft := bignum / math.Max(1, float64(kd)) 1203 // The reference LAPACK has 1204 // tscal := bignum * (float64(kd) / float64(kd+1)) 1205 // but this causes overflow when computing cnorm in Dlatbs. Our choice 1206 // is more conservative but increases coverage in the same way as the 1207 // LAPACK version. 1208 tscal := bignum / math.Max(1, float64(kd)) 1209 if uplo == blas.Upper { 1210 for i := 0; i < n; i++ { 1211 for j := 0; j < min(n-i, kd+1); j++ { 1212 r := uniformM11() 1213 ab[i*ldab+j] = math.Copysign(tleft, r) + tscal*r 1214 } 1215 } 1216 } else { 1217 for i := 0; i < n; i++ { 1218 for j := max(0, kd-i); j < kd+1; j++ { 1219 r := uniformM11() 1220 ab[i*ldab+j] = math.Copysign(tleft, r) + tscal*r 1221 } 1222 } 1223 } 1224 bi.Dscal(n, 2, b, 1) 1225 } 1226 1227 // Flip the matrix if the transpose will be used. 1228 if trans != blas.NoTrans { 1229 if uplo == blas.Upper { 1230 for j := 0; j < n/2; j++ { 1231 jlen := min(n-2*j-1, kd+1) 1232 bi.Dswap(jlen, ab[j*ldab:], 1, ab[(n-j-jlen)*ldab+jlen-1:], min(-ldab+1, -1)) 1233 } 1234 } else { 1235 for j := 0; j < n/2; j++ { 1236 jlen := min(n-2*j-1, kd+1) 1237 bi.Dswap(jlen, ab[j*ldab+kd:], max(ldab-1, 1), ab[(n-j-1)*ldab+kd+1-jlen:], -1) 1238 } 1239 } 1240 } 1241 1242 return diag, b 1243 }