github.com/gopherd/gonum@v0.0.4/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 "math/rand" 11 12 "github.com/gopherd/gonum/blas" 13 "github.com/gopherd/gonum/blas/blas64" 14 "github.com/gopherd/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 const ( 345 tiny = safmin 346 huge = (1 - ulp) / tiny 347 ) 348 349 bi := blas64.Implementation() 350 351 switch imat { 352 default: 353 // TODO(vladimir-ch): Implement the remaining cases. 354 panic("testlapack: invalid or unimplemented imat") 355 case 7: 356 // Identity matrix. The diagonal is set to NaN. 357 diag = blas.Unit 358 switch uplo { 359 case blas.Upper: 360 for i := 0; i < n; i++ { 361 a[i*lda+i] = math.NaN() 362 for j := i + 1; j < n; j++ { 363 a[i*lda+j] = 0 364 } 365 } 366 case blas.Lower: 367 for i := 0; i < n; i++ { 368 for j := 0; j < i; j++ { 369 a[i*lda+j] = 0 370 } 371 a[i*lda+i] = math.NaN() 372 } 373 } 374 case 11: 375 // Generate a triangular matrix with elements between -1 and 1, 376 // give the diagonal norm 2 to make it well-conditioned, and 377 // make the right hand side large so that it requires scaling. 378 diag = blas.NonUnit 379 switch uplo { 380 case blas.Upper: 381 for i := 0; i < n-1; i++ { 382 dlarnv(a[i*lda+i:i*lda+n], 2, rnd) 383 } 384 case blas.Lower: 385 for i := 1; i < n; i++ { 386 dlarnv(a[i*lda:i*lda+i+1], 2, rnd) 387 } 388 } 389 for i := 0; i < n; i++ { 390 a[i*lda+i] = math.Copysign(2, a[i*lda+i]) 391 } 392 // Set the right hand side so that the largest value is huge. 393 dlarnv(b, 2, rnd) 394 imax := bi.Idamax(n, b, 1) 395 bscal := huge / math.Max(1, b[imax]) 396 bi.Dscal(n, bscal, b, 1) 397 case 12: 398 // Make the first diagonal element in the solve small to cause 399 // immediate overflow when dividing by T[j,j]. The off-diagonal 400 // elements are small (cnorm[j] < 1). 401 diag = blas.NonUnit 402 tscal := 1 / math.Max(1, float64(n-1)) 403 switch uplo { 404 case blas.Upper: 405 for i := 0; i < n; i++ { 406 dlarnv(a[i*lda+i:i*lda+n], 2, rnd) 407 bi.Dscal(n-i-1, tscal, a[i*lda+i+1:], 1) 408 a[i*lda+i] = math.Copysign(1, a[i*lda+i]) 409 } 410 a[(n-1)*lda+n-1] *= tiny 411 case blas.Lower: 412 for i := 0; i < n; i++ { 413 dlarnv(a[i*lda:i*lda+i+1], 2, rnd) 414 bi.Dscal(i, tscal, a[i*lda:], 1) 415 a[i*lda+i] = math.Copysign(1, a[i*lda+i]) 416 } 417 a[0] *= tiny 418 } 419 dlarnv(b, 2, rnd) 420 case 13: 421 // Make the first diagonal element in the solve small to cause 422 // immediate overflow when dividing by T[j,j]. The off-diagonal 423 // elements are O(1) (cnorm[j] > 1). 424 diag = blas.NonUnit 425 switch uplo { 426 case blas.Upper: 427 for i := 0; i < n; i++ { 428 dlarnv(a[i*lda+i:i*lda+n], 2, rnd) 429 a[i*lda+i] = math.Copysign(1, a[i*lda+i]) 430 } 431 a[(n-1)*lda+n-1] *= tiny 432 case blas.Lower: 433 for i := 0; i < n; i++ { 434 dlarnv(a[i*lda:i*lda+i+1], 2, rnd) 435 a[i*lda+i] = math.Copysign(1, a[i*lda+i]) 436 } 437 a[0] *= tiny 438 } 439 dlarnv(b, 2, rnd) 440 case 14: 441 // T is diagonal with small numbers on the diagonal to 442 // make the growth factor underflow, but a small right hand side 443 // chosen so that the solution does not overflow. 444 diag = blas.NonUnit 445 switch uplo { 446 case blas.Upper: 447 for i := 0; i < n; i++ { 448 for j := i + 1; j < n; j++ { 449 a[i*lda+j] = 0 450 } 451 if (n-1-i)&0x2 == 0 { 452 a[i*lda+i] = tiny 453 } else { 454 a[i*lda+i] = 1 455 } 456 } 457 case blas.Lower: 458 for i := 0; i < n; i++ { 459 for j := 0; j < i; j++ { 460 a[i*lda+j] = 0 461 } 462 if i&0x2 == 0 { 463 a[i*lda+i] = tiny 464 } else { 465 a[i*lda+i] = 1 466 } 467 } 468 } 469 // Set the right hand side alternately zero and small. 470 switch uplo { 471 case blas.Upper: 472 b[0] = 0 473 for i := n - 1; i > 0; i -= 2 { 474 b[i] = 0 475 b[i-1] = tiny 476 } 477 case blas.Lower: 478 for i := 0; i < n-1; i += 2 { 479 b[i] = 0 480 b[i+1] = tiny 481 } 482 b[n-1] = 0 483 } 484 case 15: 485 // Make the diagonal elements small to cause gradual overflow 486 // when dividing by T[j,j]. To control the amount of scaling 487 // needed, the matrix is bidiagonal. 488 diag = blas.NonUnit 489 texp := 1 / math.Max(1, float64(n-1)) 490 tscal := math.Pow(tiny, texp) 491 switch uplo { 492 case blas.Upper: 493 for i := 0; i < n; i++ { 494 a[i*lda+i] = tscal 495 if i < n-1 { 496 a[i*lda+i+1] = -1 497 } 498 for j := i + 2; j < n; j++ { 499 a[i*lda+j] = 0 500 } 501 } 502 case blas.Lower: 503 for i := 0; i < n; i++ { 504 for j := 0; j < i-1; j++ { 505 a[i*lda+j] = 0 506 } 507 if i > 0 { 508 a[i*lda+i-1] = -1 509 } 510 a[i*lda+i] = tscal 511 } 512 } 513 dlarnv(b, 2, rnd) 514 case 16: 515 // One zero diagonal element. 516 diag = blas.NonUnit 517 switch uplo { 518 case blas.Upper: 519 for i := 0; i < n; i++ { 520 dlarnv(a[i*lda+i:i*lda+n], 2, rnd) 521 a[i*lda+i] = math.Copysign(2, a[i*lda+i]) 522 } 523 case blas.Lower: 524 for i := 0; i < n; i++ { 525 dlarnv(a[i*lda:i*lda+i+1], 2, rnd) 526 a[i*lda+i] = math.Copysign(2, a[i*lda+i]) 527 } 528 } 529 iy := n / 2 530 a[iy*lda+iy] = 0 531 dlarnv(b, 2, rnd) 532 bi.Dscal(n, 2, b, 1) 533 case 17: 534 // Make the offdiagonal elements large to cause overflow when 535 // adding a column of T. In the non-transposed case, the matrix 536 // is constructed to cause overflow when adding a column in 537 // every other step. 538 diag = blas.NonUnit 539 tscal := (1 - ulp) / tiny 540 texp := 1.0 541 switch uplo { 542 case blas.Upper: 543 for i := 0; i < n; i++ { 544 for j := i; j < n; j++ { 545 a[i*lda+j] = 0 546 } 547 } 548 for j := n - 1; j >= 1; j -= 2 { 549 a[j] = -tscal / float64(n+1) 550 a[j*lda+j] = 1 551 b[j] = texp * (1 - ulp) 552 a[j-1] = -tscal / float64(n+1) / float64(n+2) 553 a[(j-1)*lda+j-1] = 1 554 b[j-1] = texp * float64(n*n+n-1) 555 texp *= 2 556 } 557 b[0] = float64(n+1) / float64(n+2) * tscal 558 case blas.Lower: 559 for i := 0; i < n; i++ { 560 for j := 0; j <= i; j++ { 561 a[i*lda+j] = 0 562 } 563 } 564 for j := 0; j < n-1; j += 2 { 565 a[(n-1)*lda+j] = -tscal / float64(n+1) 566 a[j*lda+j] = 1 567 b[j] = texp * (1 - ulp) 568 a[(n-1)*lda+j+1] = -tscal / float64(n+1) / float64(n+2) 569 a[(j+1)*lda+j+1] = 1 570 b[j+1] = texp * float64(n*n+n-1) 571 texp *= 2 572 } 573 b[n-1] = float64(n+1) / float64(n+2) * tscal 574 } 575 case 18: 576 // Generate a unit triangular matrix with elements between -1 577 // and 1, and make the right hand side large so that it requires 578 // scaling. The diagonal is set to NaN. 579 diag = blas.Unit 580 switch uplo { 581 case blas.Upper: 582 for i := 0; i < n; i++ { 583 a[i*lda+i] = math.NaN() 584 dlarnv(a[i*lda+i+1:i*lda+n], 2, rnd) 585 } 586 case blas.Lower: 587 for i := 0; i < n; i++ { 588 dlarnv(a[i*lda:i*lda+i], 2, rnd) 589 a[i*lda+i] = math.NaN() 590 } 591 } 592 // Set the right hand side so that the largest value is huge. 593 dlarnv(b, 2, rnd) 594 iy := bi.Idamax(n, b, 1) 595 bnorm := math.Abs(b[iy]) 596 bscal := huge / math.Max(1, bnorm) 597 bi.Dscal(n, bscal, b, 1) 598 case 19: 599 // Generate a triangular matrix with elements between 600 // huge/(n-1) and huge so that at least one of the column 601 // norms will exceed huge. 602 // Dlatrs cannot handle this case for (typically) n>5. 603 diag = blas.NonUnit 604 tleft := huge / math.Max(1, float64(n-1)) 605 tscal := huge * (float64(n-1) / math.Max(1, float64(n))) 606 switch uplo { 607 case blas.Upper: 608 for i := 0; i < n; i++ { 609 dlarnv(a[i*lda+i:i*lda+n], 2, rnd) 610 for j := i; j < n; j++ { 611 aij := a[i*lda+j] 612 a[i*lda+j] = math.Copysign(tleft, aij) + tscal*aij 613 } 614 } 615 case blas.Lower: 616 for i := 0; i < n; i++ { 617 dlarnv(a[i*lda:i*lda+i+1], 2, rnd) 618 for j := 0; j <= i; j++ { 619 aij := a[i*lda+j] 620 a[i*lda+j] = math.Copysign(tleft, aij) + tscal*aij 621 } 622 } 623 } 624 dlarnv(b, 2, rnd) 625 bi.Dscal(n, 2, b, 1) 626 } 627 628 // Flip the matrix if the transpose will be used. 629 if trans == blas.Trans { 630 switch uplo { 631 case blas.Upper: 632 for j := 0; j < n/2; j++ { 633 bi.Dswap(n-2*j-1, a[j*lda+j:], 1, a[(j+1)*lda+n-j-1:], -lda) 634 } 635 case blas.Lower: 636 for j := 0; j < n/2; j++ { 637 bi.Dswap(n-2*j-1, a[j*lda+j:], lda, a[(n-j-1)*lda+j+1:], -1) 638 } 639 } 640 } 641 642 return diag 643 } 644 645 func checkMatrix(m, n int, a []float64, lda int) { 646 if m < 0 { 647 panic("testlapack: m < 0") 648 } 649 if n < 0 { 650 panic("testlapack: n < 0") 651 } 652 if lda < max(1, n) { 653 panic("testlapack: lda < max(1, n)") 654 } 655 if len(a) < (m-1)*lda+n { 656 panic("testlapack: insufficient matrix slice length") 657 } 658 } 659 660 // randomOrthogonal returns an n×n random orthogonal matrix. 661 func randomOrthogonal(n int, rnd *rand.Rand) blas64.General { 662 q := eye(n, n) 663 x := make([]float64, n) 664 v := make([]float64, n) 665 for j := 0; j < n-1; j++ { 666 // x represents the j-th column of a random matrix. 667 for i := 0; i < j; i++ { 668 x[i] = 0 669 } 670 for i := j; i < n; i++ { 671 x[i] = rnd.NormFloat64() 672 } 673 // Compute v that represents the elementary reflector that 674 // annihilates the subdiagonal elements of x. 675 reflector(v, x, j) 676 // Compute Q * H_j and store the result into Q. 677 applyReflector(q, q, v) 678 } 679 return q 680 } 681 682 // reflector generates a Householder reflector v that zeros out subdiagonal 683 // entries in the j-th column of a matrix. 684 func reflector(v, col []float64, j int) { 685 n := len(col) 686 if len(v) != n { 687 panic("slice length mismatch") 688 } 689 if j < 0 || n <= j { 690 panic("invalid column index") 691 } 692 693 for i := range v { 694 v[i] = 0 695 } 696 if j == n-1 { 697 return 698 } 699 s := floats.Norm(col[j:], 2) 700 if s == 0 { 701 return 702 } 703 v[j] = col[j] + math.Copysign(s, col[j]) 704 copy(v[j+1:], col[j+1:]) 705 s = floats.Norm(v[j:], 2) 706 floats.Scale(1/s, v[j:]) 707 } 708 709 // applyReflector computes Q*H where H is a Householder matrix represented by 710 // the Householder reflector v. 711 func applyReflector(qh blas64.General, q blas64.General, v []float64) { 712 n := len(v) 713 if qh.Rows != n || qh.Cols != n { 714 panic("bad size of qh") 715 } 716 if q.Rows != n || q.Cols != n { 717 panic("bad size of q") 718 } 719 qv := make([]float64, n) 720 blas64.Gemv(blas.NoTrans, 1, q, blas64.Vector{Data: v, Inc: 1}, 0, blas64.Vector{Data: qv, Inc: 1}) 721 for i := 0; i < n; i++ { 722 for j := 0; j < n; j++ { 723 qh.Data[i*qh.Stride+j] = q.Data[i*q.Stride+j] 724 } 725 } 726 for i := 0; i < n; i++ { 727 for j := 0; j < n; j++ { 728 qh.Data[i*qh.Stride+j] -= 2 * qv[i] * v[j] 729 } 730 } 731 var norm2 float64 732 for _, vi := range v { 733 norm2 += vi * vi 734 } 735 norm2inv := 1 / norm2 736 for i := 0; i < n; i++ { 737 for j := 0; j < n; j++ { 738 qh.Data[i*qh.Stride+j] *= norm2inv 739 } 740 } 741 } 742 743 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) { 744 switch { 745 case kind < 1 || 18 < kind: 746 panic("bad matrix kind") 747 case (6 <= kind && kind <= 9) || kind == 17: 748 diag = blas.Unit 749 default: 750 diag = blas.NonUnit 751 } 752 753 if n == 0 { 754 return 755 } 756 757 const ( 758 tiny = safmin 759 huge = (1 - ulp) / tiny 760 761 small = 0.25 * (safmin / ulp) 762 large = 1 / small 763 badc2 = 0.1 / ulp 764 ) 765 badc1 := math.Sqrt(badc2) 766 767 var cndnum float64 768 switch { 769 case kind == 2 || kind == 8: 770 cndnum = badc1 771 case kind == 3 || kind == 9: 772 cndnum = badc2 773 default: 774 cndnum = 2 775 } 776 777 uniformM11 := func() float64 { 778 return 2*rnd.Float64() - 1 779 } 780 781 // Allocate the right-hand side and fill it with random numbers. 782 // The pathological matrix types below overwrite it with their 783 // custom vector. 784 b = make([]float64, n) 785 for i := range b { 786 b[i] = uniformM11() 787 } 788 789 bi := blas64.Implementation() 790 switch kind { 791 default: 792 panic("test matrix type not implemented") 793 794 case 1, 2, 3, 4, 5: 795 // Non-unit triangular matrix 796 // TODO(vladimir-ch) 797 var kl, ku int 798 switch uplo { 799 case blas.Upper: 800 ku = kd 801 kl = 0 802 // IOFF = 1 + MAX( 0, KD-N+1 ) 803 // PACKIT = 'Q' 804 // 'Q' => store the upper triangle in band storage scheme 805 // (only if matrix symmetric or upper triangular) 806 case blas.Lower: 807 ku = 0 808 kl = kd 809 // IOFF = 1 810 // PACKIT = 'B' 811 // 'B' => store the lower triangle in band storage scheme 812 // (only if matrix symmetric or lower triangular) 813 } 814 anorm := 1.0 815 switch kind { 816 case 4: 817 anorm = small 818 case 5: 819 anorm = large 820 } 821 _, _, _ = kl, ku, anorm 822 // // DIST = 'S' // UNIFORM(-1, 1) 823 // // MODE = 3 // MODE = 3 sets D(I)=CNDNUM**(-(I-1)/(N-1)) 824 // // TYPE = 'N' // If TYPE='N', the generated matrix is nonsymmetric 825 // CALL DLATMS( N, N, DIST, ISEED, TYPE, B, MODE, CNDNUM, ANORM, 826 // $ KL, KU, PACKIT, AB( IOFF, 1 ), LDAB, WORK, INFO ) 827 panic("test matrix type not implemented") 828 829 case 6: 830 // Matrix is the identity. 831 if uplo == blas.Upper { 832 for i := 0; i < n; i++ { 833 // Fill the diagonal with non-unit numbers. 834 ab[i*ldab] = float64(i + 2) 835 for j := 1; j < min(n-i, kd+1); j++ { 836 ab[i*ldab+j] = 0 837 } 838 } 839 } else { 840 for i := 0; i < n; i++ { 841 for j := max(0, kd-i); j < kd; j++ { 842 ab[i*ldab+j] = 0 843 } 844 // Fill the diagonal with non-unit numbers. 845 ab[i*ldab+kd] = float64(i + 2) 846 } 847 } 848 849 case 7, 8, 9: 850 // Non-trivial unit triangular matrix 851 // 852 // A unit triangular matrix T with condition cndnum is formed. 853 // In this version, T only has bandwidth 2, the rest of it is 854 // zero. 855 856 tnorm := math.Sqrt(cndnum) 857 858 // Initialize AB to zero. 859 if uplo == blas.Upper { 860 for i := 0; i < n; i++ { 861 // Fill the diagonal with non-unit numbers. 862 ab[i*ldab] = float64(i + 2) 863 for j := 1; j < min(n-i, kd+1); j++ { 864 ab[i*ldab+j] = 0 865 } 866 } 867 } else { 868 for i := 0; i < n; i++ { 869 for j := max(0, kd-i); j < kd; j++ { 870 ab[i*ldab+j] = 0 871 } 872 // Fill the diagonal with non-unit numbers. 873 ab[i*ldab+kd] = float64(i + 2) 874 } 875 } 876 877 switch kd { 878 case 0: 879 // Unit diagonal matrix, nothing else to do. 880 case 1: 881 // Special case: T is tridiagonal. Set every other 882 // off-diagonal so that the matrix has norm tnorm+1. 883 if n > 1 { 884 if uplo == blas.Upper { 885 ab[1] = math.Copysign(tnorm, uniformM11()) 886 for i := 2; i < n-1; i += 2 { 887 ab[i*ldab+1] = tnorm * uniformM11() 888 } 889 } else { 890 ab[ldab] = math.Copysign(tnorm, uniformM11()) 891 for i := 3; i < n; i += 2 { 892 ab[i*ldab] = tnorm * uniformM11() 893 } 894 } 895 } 896 default: 897 // Form a unit triangular matrix T with condition cndnum. T is given 898 // by 899 // | 1 + * | 900 // | 1 + | 901 // T = | 1 + * | 902 // | 1 + | 903 // | 1 + * | 904 // | 1 + | 905 // | . . . | 906 // Each element marked with a '*' is formed by taking the product of 907 // the adjacent elements marked with '+'. The '*'s can be chosen 908 // freely, and the '+'s are chosen so that the inverse of T will 909 // have elements of the same magnitude as T. 910 work1 := make([]float64, n) 911 work2 := make([]float64, n) 912 star1 := math.Copysign(tnorm, uniformM11()) 913 sfac := math.Sqrt(tnorm) 914 plus1 := math.Copysign(sfac, uniformM11()) 915 for i := 0; i < n; i += 2 { 916 work1[i] = plus1 917 work2[i] = star1 918 if i+1 == n { 919 continue 920 } 921 plus2 := star1 / plus1 922 work1[i+1] = plus2 923 plus1 = star1 / plus2 924 // Generate a new *-value with norm between sqrt(tnorm) 925 // and tnorm. 926 rexp := uniformM11() 927 if rexp < 0 { 928 star1 = -math.Pow(sfac, 1-rexp) 929 } else { 930 star1 = math.Pow(sfac, 1+rexp) 931 } 932 } 933 // Copy the diagonal to AB. 934 if uplo == blas.Upper { 935 bi.Dcopy(n-1, work1, 1, ab[1:], ldab) 936 if n > 2 { 937 bi.Dcopy(n-2, work2, 1, ab[2:], ldab) 938 } 939 } else { 940 bi.Dcopy(n-1, work1, 1, ab[ldab+kd-1:], ldab) 941 if n > 2 { 942 bi.Dcopy(n-2, work2, 1, ab[2*ldab+kd-2:], ldab) 943 } 944 } 945 } 946 947 // Pathological test cases 10-18: these triangular matrices are badly 948 // scaled or badly conditioned, so when used in solving a triangular 949 // system they may cause overflow in the solution vector. 950 951 case 10: 952 // Generate a triangular matrix with elements between -1 and 1. 953 // Give the diagonal norm 2 to make it well-conditioned. 954 // Make the right hand side large so that it requires scaling. 955 if uplo == blas.Upper { 956 for i := 0; i < n; i++ { 957 for j := 0; j < min(n-j, kd+1); j++ { 958 ab[i*ldab+j] = uniformM11() 959 } 960 ab[i*ldab] = math.Copysign(2, ab[i*ldab]) 961 } 962 } else { 963 for i := 0; i < n; i++ { 964 for j := max(0, kd-i); j < kd+1; j++ { 965 ab[i*ldab+j] = uniformM11() 966 } 967 ab[i*ldab+kd] = math.Copysign(2, ab[i*ldab+kd]) 968 } 969 } 970 // Set the right hand side so that the largest value is huge. 971 bnorm := math.Abs(b[bi.Idamax(n, b, 1)]) 972 bscal := huge / math.Max(1, bnorm) 973 bi.Dscal(n, bscal, b, 1) 974 975 case 11: 976 // Make the first diagonal element in the solve small to cause 977 // immediate overflow when dividing by T[j,j]. 978 // The offdiagonal elements are small (cnorm[j] < 1). 979 tscal := 1 / float64(kd+1) 980 if uplo == blas.Upper { 981 for i := 0; i < n; i++ { 982 jlen := min(n-i, kd+1) 983 arow := ab[i*ldab : i*ldab+jlen] 984 dlarnv(arow, 2, rnd) 985 if jlen > 1 { 986 bi.Dscal(jlen-1, tscal, arow[1:], 1) 987 } 988 ab[i*ldab] = math.Copysign(1, ab[i*ldab]) 989 } 990 ab[(n-1)*ldab] *= tiny 991 } else { 992 for i := 0; i < n; i++ { 993 jlen := min(i+1, kd+1) 994 arow := ab[i*ldab+kd+1-jlen : i*ldab+kd+1] 995 dlarnv(arow, 2, rnd) 996 if jlen > 1 { 997 bi.Dscal(jlen-1, tscal, arow[:jlen-1], 1) 998 } 999 ab[i*ldab+kd] = math.Copysign(1, ab[i*ldab+kd]) 1000 } 1001 ab[kd] *= tiny 1002 } 1003 1004 case 12: 1005 // Make the first diagonal element in the solve small to cause 1006 // immediate overflow when dividing by T[j,j]. 1007 // The offdiagonal elements are O(1) (cnorm[j] > 1). 1008 if uplo == blas.Upper { 1009 for i := 0; i < n; i++ { 1010 jlen := min(n-i, kd+1) 1011 arow := ab[i*ldab : i*ldab+jlen] 1012 dlarnv(arow, 2, rnd) 1013 ab[i*ldab] = math.Copysign(1, ab[i*ldab]) 1014 } 1015 ab[(n-1)*ldab] *= tiny 1016 } else { 1017 for i := 0; i < n; i++ { 1018 jlen := min(i+1, kd+1) 1019 arow := ab[i*ldab+kd+1-jlen : i*ldab+kd+1] 1020 dlarnv(arow, 2, rnd) 1021 ab[i*ldab+kd] = math.Copysign(1, ab[i*ldab+kd]) 1022 } 1023 ab[kd] *= tiny 1024 } 1025 1026 case 13: 1027 // T is diagonal with small numbers on the diagonal to make the growth 1028 // factor underflow, but a small right hand side chosen so that the 1029 // solution does not overflow. 1030 if uplo == blas.Upper { 1031 icount := 1 1032 for i := n - 1; i >= 0; i-- { 1033 if icount <= 2 { 1034 ab[i*ldab] = tiny 1035 } else { 1036 ab[i*ldab] = 1 1037 } 1038 for j := 1; j < min(n-i, kd+1); j++ { 1039 ab[i*ldab+j] = 0 1040 } 1041 icount++ 1042 if icount > 4 { 1043 icount = 1 1044 } 1045 } 1046 } else { 1047 icount := 1 1048 for i := 0; i < n; i++ { 1049 for j := max(0, kd-i); j < kd; j++ { 1050 ab[i*ldab+j] = 0 1051 } 1052 if icount <= 2 { 1053 ab[i*ldab+kd] = tiny 1054 } else { 1055 ab[i*ldab+kd] = 1 1056 } 1057 icount++ 1058 if icount > 4 { 1059 icount = 1 1060 } 1061 } 1062 } 1063 // Set the right hand side alternately zero and small. 1064 if uplo == blas.Upper { 1065 b[0] = 0 1066 for i := n - 1; i > 1; i -= 2 { 1067 b[i] = 0 1068 b[i-1] = tiny 1069 } 1070 } else { 1071 b[n-1] = 0 1072 for i := 0; i < n-1; i += 2 { 1073 b[i] = 0 1074 b[i+1] = tiny 1075 } 1076 } 1077 1078 case 14: 1079 // Make the diagonal elements small to cause gradual overflow when 1080 // dividing by T[j,j]. To control the amount of scaling needed, the 1081 // matrix is bidiagonal. 1082 tscal := math.Pow(tiny, 1/float64(kd+1)) 1083 if uplo == blas.Upper { 1084 for i := 0; i < n; i++ { 1085 ab[i*ldab] = tscal 1086 if i < n-1 && kd > 0 { 1087 ab[i*ldab+1] = -1 1088 } 1089 for j := 2; j < min(n-i, kd+1); j++ { 1090 ab[i*ldab+j] = 0 1091 } 1092 } 1093 b[n-1] = 1 1094 } else { 1095 for i := 0; i < n; i++ { 1096 for j := max(0, kd-i); j < kd-1; j++ { 1097 ab[i*ldab+j] = 0 1098 } 1099 if i > 0 && kd > 0 { 1100 ab[i*ldab+kd-1] = -1 1101 } 1102 ab[i*ldab+kd] = tscal 1103 } 1104 b[0] = 1 1105 } 1106 1107 case 15: 1108 // One zero diagonal element. 1109 iy := n / 2 1110 if uplo == blas.Upper { 1111 for i := 0; i < n; i++ { 1112 jlen := min(n-i, kd+1) 1113 dlarnv(ab[i*ldab:i*ldab+jlen], 2, rnd) 1114 if i != iy { 1115 ab[i*ldab] = math.Copysign(2, ab[i*ldab]) 1116 } else { 1117 ab[i*ldab] = 0 1118 } 1119 } 1120 } else { 1121 for i := 0; i < n; i++ { 1122 jlen := min(i+1, kd+1) 1123 dlarnv(ab[i*ldab+kd+1-jlen:i*ldab+kd+1], 2, rnd) 1124 if i != iy { 1125 ab[i*ldab+kd] = math.Copysign(2, ab[i*ldab+kd]) 1126 } else { 1127 ab[i*ldab+kd] = 0 1128 } 1129 } 1130 } 1131 bi.Dscal(n, 2, b, 1) 1132 1133 // case 16: 1134 // TODO(vladimir-ch) 1135 // Make the off-diagonal elements large to cause overflow when adding a 1136 // column of T. In the non-transposed case, the matrix is constructed to 1137 // cause overflow when adding a column in every other step. 1138 1139 // Initialize the matrix to zero. 1140 // if uplo == blas.Upper { 1141 // for i := 0; i < n; i++ { 1142 // for j := 0; j < min(n-i, kd+1); j++ { 1143 // ab[i*ldab+j] = 0 1144 // } 1145 // } 1146 // } else { 1147 // for i := 0; i < n; i++ { 1148 // for j := max(0, kd-i); j < kd+1; j++ { 1149 // ab[i*ldab+j] = 0 1150 // } 1151 // } 1152 // } 1153 1154 // const tscal = (1 - ulp) / (unfl / ulp) 1155 // texp := 1.0 1156 // if kd > 0 { 1157 // if uplo == blas.Upper { 1158 // for j := n - 1; j >= 0; j -= kd { 1159 // } 1160 // } else { 1161 // for j := 0; j < n; j += kd { 1162 // } 1163 // } 1164 // } else { 1165 // // Diagonal matrix. 1166 // for i := 0; i < n; i++ { 1167 // ab[i*ldab] = 1 1168 // b[i] = float64(i + 1) 1169 // } 1170 // } 1171 1172 case 17: 1173 // Generate a unit triangular matrix with elements between -1 and 1, and 1174 // make the right hand side large so that it requires scaling. 1175 if uplo == blas.Upper { 1176 for i := 0; i < n; i++ { 1177 ab[i*ldab] = float64(i + 2) 1178 jlen := min(n-i-1, kd) 1179 if jlen > 0 { 1180 dlarnv(ab[i*ldab+1:i*ldab+1+jlen], 2, rnd) 1181 } 1182 } 1183 } else { 1184 for i := 0; i < n; i++ { 1185 jlen := min(i, kd) 1186 if jlen > 0 { 1187 dlarnv(ab[i*ldab+kd-jlen:i*ldab+kd], 2, rnd) 1188 } 1189 ab[i*ldab+kd] = float64(i + 2) 1190 } 1191 } 1192 // Set the right hand side so that the largest value is huge. 1193 bnorm := math.Abs(b[bi.Idamax(n, b, 1)]) 1194 bscal := huge / math.Max(1, bnorm) 1195 bi.Dscal(n, bscal, b, 1) 1196 1197 case 18: 1198 // Generate a triangular matrix with elements between huge/kd and 1199 // huge so that at least one of the column norms will exceed huge. 1200 tleft := huge / math.Max(1, float64(kd)) 1201 // The reference LAPACK has 1202 // tscal := huge * (float64(kd) / float64(kd+1)) 1203 // but this causes overflow when computing cnorm in Dlatbs. Our choice 1204 // is more conservative but increases coverage in the same way as the 1205 // LAPACK version. 1206 tscal := huge / math.Max(1, float64(kd)) 1207 if uplo == blas.Upper { 1208 for i := 0; i < n; i++ { 1209 for j := 0; j < min(n-i, kd+1); j++ { 1210 r := uniformM11() 1211 ab[i*ldab+j] = math.Copysign(tleft, r) + tscal*r 1212 } 1213 } 1214 } else { 1215 for i := 0; i < n; i++ { 1216 for j := max(0, kd-i); j < kd+1; j++ { 1217 r := uniformM11() 1218 ab[i*ldab+j] = math.Copysign(tleft, r) + tscal*r 1219 } 1220 } 1221 } 1222 bi.Dscal(n, 2, b, 1) 1223 } 1224 1225 // Flip the matrix if the transpose will be used. 1226 if trans != blas.NoTrans { 1227 if uplo == blas.Upper { 1228 for j := 0; j < n/2; j++ { 1229 jlen := min(n-2*j-1, kd+1) 1230 bi.Dswap(jlen, ab[j*ldab:], 1, ab[(n-j-jlen)*ldab+jlen-1:], min(-ldab+1, -1)) 1231 } 1232 } else { 1233 for j := 0; j < n/2; j++ { 1234 jlen := min(n-2*j-1, kd+1) 1235 bi.Dswap(jlen, ab[j*ldab+kd:], max(ldab-1, 1), ab[(n-j-1)*ldab+kd+1-jlen:], -1) 1236 } 1237 } 1238 } 1239 1240 return diag, b 1241 }