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