gonum.org/v1/gonum@v0.14.0/blas/gonum/level1float64.go (about) 1 // Copyright ©2015 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package gonum 6 7 import ( 8 "math" 9 10 "gonum.org/v1/gonum/blas" 11 "gonum.org/v1/gonum/internal/asm/f64" 12 ) 13 14 var _ blas.Float64Level1 = Implementation{} 15 16 // Dnrm2 computes the Euclidean norm of a vector, 17 // 18 // sqrt(\sum_i x[i] * x[i]). 19 // 20 // This function returns 0 if incX is negative. 21 func (Implementation) Dnrm2(n int, x []float64, incX int) float64 { 22 if incX < 1 { 23 if incX == 0 { 24 panic(zeroIncX) 25 } 26 return 0 27 } 28 if len(x) <= (n-1)*incX { 29 panic(shortX) 30 } 31 if n < 2 { 32 if n == 1 { 33 return math.Abs(x[0]) 34 } 35 if n == 0 { 36 return 0 37 } 38 panic(nLT0) 39 } 40 if incX == 1 { 41 return f64.L2NormUnitary(x[:n]) 42 } 43 return f64.L2NormInc(x, uintptr(n), uintptr(incX)) 44 } 45 46 // Dasum computes the sum of the absolute values of the elements of x. 47 // 48 // \sum_i |x[i]| 49 // 50 // Dasum returns 0 if incX is negative. 51 func (Implementation) Dasum(n int, x []float64, incX int) float64 { 52 var sum float64 53 if n < 0 { 54 panic(nLT0) 55 } 56 if incX < 1 { 57 if incX == 0 { 58 panic(zeroIncX) 59 } 60 return 0 61 } 62 if len(x) <= (n-1)*incX { 63 panic(shortX) 64 } 65 if incX == 1 { 66 x = x[:n] 67 for _, v := range x { 68 sum += math.Abs(v) 69 } 70 return sum 71 } 72 for i := 0; i < n; i++ { 73 sum += math.Abs(x[i*incX]) 74 } 75 return sum 76 } 77 78 // Idamax returns the index of an element of x with the largest absolute value. 79 // If there are multiple such indices the earliest is returned. 80 // Idamax returns -1 if n == 0. 81 func (Implementation) Idamax(n int, x []float64, incX int) int { 82 if incX < 1 { 83 if incX == 0 { 84 panic(zeroIncX) 85 } 86 return -1 87 } 88 if len(x) <= (n-1)*incX { 89 panic(shortX) 90 } 91 if n < 2 { 92 if n == 1 { 93 return 0 94 } 95 if n == 0 { 96 return -1 // Netlib returns invalid index when n == 0. 97 } 98 panic(nLT0) 99 } 100 idx := 0 101 max := math.Abs(x[0]) 102 if incX == 1 { 103 for i, v := range x[:n] { 104 absV := math.Abs(v) 105 if absV > max { 106 max = absV 107 idx = i 108 } 109 } 110 return idx 111 } 112 ix := incX 113 for i := 1; i < n; i++ { 114 v := x[ix] 115 absV := math.Abs(v) 116 if absV > max { 117 max = absV 118 idx = i 119 } 120 ix += incX 121 } 122 return idx 123 } 124 125 // Dswap exchanges the elements of two vectors. 126 // 127 // x[i], y[i] = y[i], x[i] for all i 128 func (Implementation) Dswap(n int, x []float64, incX int, y []float64, incY int) { 129 if incX == 0 { 130 panic(zeroIncX) 131 } 132 if incY == 0 { 133 panic(zeroIncY) 134 } 135 if n < 1 { 136 if n == 0 { 137 return 138 } 139 panic(nLT0) 140 } 141 if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { 142 panic(shortX) 143 } 144 if (incY > 0 && len(y) <= (n-1)*incY) || (incY < 0 && len(y) <= (1-n)*incY) { 145 panic(shortY) 146 } 147 if incX == 1 && incY == 1 { 148 x = x[:n] 149 for i, v := range x { 150 x[i], y[i] = y[i], v 151 } 152 return 153 } 154 var ix, iy int 155 if incX < 0 { 156 ix = (-n + 1) * incX 157 } 158 if incY < 0 { 159 iy = (-n + 1) * incY 160 } 161 for i := 0; i < n; i++ { 162 x[ix], y[iy] = y[iy], x[ix] 163 ix += incX 164 iy += incY 165 } 166 } 167 168 // Dcopy copies the elements of x into the elements of y. 169 // 170 // y[i] = x[i] for all i 171 func (Implementation) Dcopy(n int, x []float64, incX int, y []float64, incY int) { 172 if incX == 0 { 173 panic(zeroIncX) 174 } 175 if incY == 0 { 176 panic(zeroIncY) 177 } 178 if n < 1 { 179 if n == 0 { 180 return 181 } 182 panic(nLT0) 183 } 184 if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { 185 panic(shortX) 186 } 187 if (incY > 0 && len(y) <= (n-1)*incY) || (incY < 0 && len(y) <= (1-n)*incY) { 188 panic(shortY) 189 } 190 if incX == 1 && incY == 1 { 191 copy(y[:n], x[:n]) 192 return 193 } 194 var ix, iy int 195 if incX < 0 { 196 ix = (-n + 1) * incX 197 } 198 if incY < 0 { 199 iy = (-n + 1) * incY 200 } 201 for i := 0; i < n; i++ { 202 y[iy] = x[ix] 203 ix += incX 204 iy += incY 205 } 206 } 207 208 // Daxpy adds alpha times x to y 209 // 210 // y[i] += alpha * x[i] for all i 211 func (Implementation) Daxpy(n int, alpha float64, x []float64, incX int, y []float64, incY int) { 212 if incX == 0 { 213 panic(zeroIncX) 214 } 215 if incY == 0 { 216 panic(zeroIncY) 217 } 218 if n < 1 { 219 if n == 0 { 220 return 221 } 222 panic(nLT0) 223 } 224 if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { 225 panic(shortX) 226 } 227 if (incY > 0 && len(y) <= (n-1)*incY) || (incY < 0 && len(y) <= (1-n)*incY) { 228 panic(shortY) 229 } 230 if alpha == 0 { 231 return 232 } 233 if incX == 1 && incY == 1 { 234 f64.AxpyUnitary(alpha, x[:n], y[:n]) 235 return 236 } 237 var ix, iy int 238 if incX < 0 { 239 ix = (-n + 1) * incX 240 } 241 if incY < 0 { 242 iy = (-n + 1) * incY 243 } 244 f64.AxpyInc(alpha, x, y, uintptr(n), uintptr(incX), uintptr(incY), uintptr(ix), uintptr(iy)) 245 } 246 247 // Drotg computes a plane rotation 248 // 249 // ⎡ c s ⎤ ⎡ a ⎤ = ⎡ r ⎤ 250 // ⎣ -s c ⎦ ⎣ b ⎦ ⎣ 0 ⎦ 251 // 252 // satisfying c^2 + s^2 = 1. 253 // 254 // The computation uses the formulas 255 // 256 // sigma = sgn(a) if |a| > |b| 257 // = sgn(b) if |b| >= |a| 258 // r = sigma*sqrt(a^2 + b^2) 259 // c = 1; s = 0 if r = 0 260 // c = a/r; s = b/r if r != 0 261 // c >= 0 if |a| > |b| 262 // 263 // The subroutine also computes 264 // 265 // z = s if |a| > |b|, 266 // = 1/c if |b| >= |a| and c != 0 267 // = 1 if c = 0 268 // 269 // This allows c and s to be reconstructed from z as follows: 270 // 271 // If z = 1, set c = 0, s = 1. 272 // If |z| < 1, set c = sqrt(1 - z^2) and s = z. 273 // If |z| > 1, set c = 1/z and s = sqrt(1 - c^2). 274 // 275 // NOTE: There is a discrepancy between the reference implementation and the 276 // BLAS technical manual regarding the sign for r when a or b are zero. Drotg 277 // agrees with the definition in the manual and other common BLAS 278 // implementations. 279 func (Implementation) Drotg(a, b float64) (c, s, r, z float64) { 280 // Implementation based on Supplemental Material to: 281 // Edward Anderson. 2017. Algorithm 978: Safe Scaling in the Level 1 BLAS. 282 // ACM Trans. Math. Softw. 44, 1, Article 12 (July 2017), 28 pages. 283 // DOI: https://doi.org/10.1145/3061665 284 const ( 285 safmin = 0x1p-1022 286 safmax = 1 / safmin 287 ) 288 anorm := math.Abs(a) 289 bnorm := math.Abs(b) 290 switch { 291 case bnorm == 0: 292 c = 1 293 s = 0 294 r = a 295 z = 0 296 case anorm == 0: 297 c = 0 298 s = 1 299 r = b 300 z = 1 301 default: 302 maxab := math.Max(anorm, bnorm) 303 scl := math.Min(math.Max(safmin, maxab), safmax) 304 var sigma float64 305 if anorm > bnorm { 306 sigma = math.Copysign(1, a) 307 } else { 308 sigma = math.Copysign(1, b) 309 } 310 ascl := a / scl 311 bscl := b / scl 312 r = sigma * (scl * math.Sqrt(ascl*ascl+bscl*bscl)) 313 c = a / r 314 s = b / r 315 switch { 316 case anorm > bnorm: 317 z = s 318 case c != 0: 319 z = 1 / c 320 default: 321 z = 1 322 } 323 } 324 return c, s, r, z 325 } 326 327 // Drotmg computes the modified Givens rotation. See 328 // http://www.netlib.org/lapack/explore-html/df/deb/drotmg_8f.html 329 // for more details. 330 func (Implementation) Drotmg(d1, d2, x1, y1 float64) (p blas.DrotmParams, rd1, rd2, rx1 float64) { 331 // The implementation of Drotmg used here is taken from Hopkins 1997 332 // Appendix A: https://doi.org/10.1145/289251.289253 333 // with the exception of the gam constants below. 334 335 const ( 336 gam = 4096.0 337 gamsq = gam * gam 338 rgamsq = 1.0 / gamsq 339 ) 340 341 if d1 < 0 { 342 p.Flag = blas.Rescaling // Error state. 343 return p, 0, 0, 0 344 } 345 346 if d2 == 0 || y1 == 0 { 347 p.Flag = blas.Identity 348 return p, d1, d2, x1 349 } 350 351 var h11, h12, h21, h22 float64 352 if (d1 == 0 || x1 == 0) && d2 > 0 { 353 p.Flag = blas.Diagonal 354 h12 = 1 355 h21 = -1 356 x1 = y1 357 d1, d2 = d2, d1 358 } else { 359 p2 := d2 * y1 360 p1 := d1 * x1 361 q2 := p2 * y1 362 q1 := p1 * x1 363 if math.Abs(q1) > math.Abs(q2) { 364 p.Flag = blas.OffDiagonal 365 h11 = 1 366 h22 = 1 367 h21 = -y1 / x1 368 h12 = p2 / p1 369 u := 1 - float64(h12*h21) 370 if u <= 0 { 371 p.Flag = blas.Rescaling // Error state. 372 return p, 0, 0, 0 373 } 374 375 d1 /= u 376 d2 /= u 377 x1 *= u 378 } else { 379 if q2 < 0 { 380 p.Flag = blas.Rescaling // Error state. 381 return p, 0, 0, 0 382 } 383 384 p.Flag = blas.Diagonal 385 h21 = -1 386 h12 = 1 387 h11 = p1 / p2 388 h22 = x1 / y1 389 u := 1 + float64(h11*h22) 390 d1, d2 = d2/u, d1/u 391 x1 = y1 * u 392 } 393 } 394 395 for d1 <= rgamsq && d1 != 0 { 396 p.Flag = blas.Rescaling 397 d1 = (d1 * gam) * gam 398 x1 /= gam 399 h11 /= gam 400 h12 /= gam 401 } 402 for d1 > gamsq { 403 p.Flag = blas.Rescaling 404 d1 = (d1 / gam) / gam 405 x1 *= gam 406 h11 *= gam 407 h12 *= gam 408 } 409 410 for math.Abs(d2) <= rgamsq && d2 != 0 { 411 p.Flag = blas.Rescaling 412 d2 = (d2 * gam) * gam 413 h21 /= gam 414 h22 /= gam 415 } 416 for math.Abs(d2) > gamsq { 417 p.Flag = blas.Rescaling 418 d2 = (d2 / gam) / gam 419 h21 *= gam 420 h22 *= gam 421 } 422 423 switch p.Flag { 424 case blas.Diagonal: 425 p.H = [4]float64{0: h11, 3: h22} 426 case blas.OffDiagonal: 427 p.H = [4]float64{1: h21, 2: h12} 428 case blas.Rescaling: 429 p.H = [4]float64{h11, h21, h12, h22} 430 default: 431 panic(badFlag) 432 } 433 434 return p, d1, d2, x1 435 } 436 437 // Drot applies a plane transformation. 438 // 439 // x[i] = c * x[i] + s * y[i] 440 // y[i] = c * y[i] - s * x[i] 441 func (Implementation) Drot(n int, x []float64, incX int, y []float64, incY int, c float64, s float64) { 442 if incX == 0 { 443 panic(zeroIncX) 444 } 445 if incY == 0 { 446 panic(zeroIncY) 447 } 448 if n < 1 { 449 if n == 0 { 450 return 451 } 452 panic(nLT0) 453 } 454 if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { 455 panic(shortX) 456 } 457 if (incY > 0 && len(y) <= (n-1)*incY) || (incY < 0 && len(y) <= (1-n)*incY) { 458 panic(shortY) 459 } 460 if incX == 1 && incY == 1 { 461 x = x[:n] 462 for i, vx := range x { 463 vy := y[i] 464 x[i], y[i] = c*vx+s*vy, c*vy-s*vx 465 } 466 return 467 } 468 var ix, iy int 469 if incX < 0 { 470 ix = (-n + 1) * incX 471 } 472 if incY < 0 { 473 iy = (-n + 1) * incY 474 } 475 for i := 0; i < n; i++ { 476 vx := x[ix] 477 vy := y[iy] 478 x[ix], y[iy] = c*vx+s*vy, c*vy-s*vx 479 ix += incX 480 iy += incY 481 } 482 } 483 484 // Drotm applies the modified Givens rotation to the 2×n matrix. 485 func (Implementation) Drotm(n int, x []float64, incX int, y []float64, incY int, p blas.DrotmParams) { 486 if incX == 0 { 487 panic(zeroIncX) 488 } 489 if incY == 0 { 490 panic(zeroIncY) 491 } 492 if n <= 0 { 493 if n == 0 { 494 return 495 } 496 panic(nLT0) 497 } 498 if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { 499 panic(shortX) 500 } 501 if (incY > 0 && len(y) <= (n-1)*incY) || (incY < 0 && len(y) <= (1-n)*incY) { 502 panic(shortY) 503 } 504 505 if p.Flag == blas.Identity { 506 return 507 } 508 509 switch p.Flag { 510 case blas.Rescaling: 511 h11 := p.H[0] 512 h12 := p.H[2] 513 h21 := p.H[1] 514 h22 := p.H[3] 515 if incX == 1 && incY == 1 { 516 x = x[:n] 517 for i, vx := range x { 518 vy := y[i] 519 x[i], y[i] = float64(vx*h11)+float64(vy*h12), float64(vx*h21)+float64(vy*h22) 520 } 521 return 522 } 523 var ix, iy int 524 if incX < 0 { 525 ix = (-n + 1) * incX 526 } 527 if incY < 0 { 528 iy = (-n + 1) * incY 529 } 530 for i := 0; i < n; i++ { 531 vx := x[ix] 532 vy := y[iy] 533 x[ix], y[iy] = float64(vx*h11)+float64(vy*h12), float64(vx*h21)+float64(vy*h22) 534 ix += incX 535 iy += incY 536 } 537 case blas.OffDiagonal: 538 h12 := p.H[2] 539 h21 := p.H[1] 540 if incX == 1 && incY == 1 { 541 x = x[:n] 542 for i, vx := range x { 543 vy := y[i] 544 x[i], y[i] = vx+float64(vy*h12), float64(vx*h21)+vy 545 } 546 return 547 } 548 var ix, iy int 549 if incX < 0 { 550 ix = (-n + 1) * incX 551 } 552 if incY < 0 { 553 iy = (-n + 1) * incY 554 } 555 for i := 0; i < n; i++ { 556 vx := x[ix] 557 vy := y[iy] 558 x[ix], y[iy] = vx+float64(vy*h12), float64(vx*h21)+vy 559 ix += incX 560 iy += incY 561 } 562 case blas.Diagonal: 563 h11 := p.H[0] 564 h22 := p.H[3] 565 if incX == 1 && incY == 1 { 566 x = x[:n] 567 for i, vx := range x { 568 vy := y[i] 569 x[i], y[i] = float64(vx*h11)+vy, -vx+float64(vy*h22) 570 } 571 return 572 } 573 var ix, iy int 574 if incX < 0 { 575 ix = (-n + 1) * incX 576 } 577 if incY < 0 { 578 iy = (-n + 1) * incY 579 } 580 for i := 0; i < n; i++ { 581 vx := x[ix] 582 vy := y[iy] 583 x[ix], y[iy] = float64(vx*h11)+vy, -vx+float64(vy*h22) 584 ix += incX 585 iy += incY 586 } 587 } 588 } 589 590 // Dscal scales x by alpha. 591 // 592 // x[i] *= alpha 593 // 594 // Dscal has no effect if incX < 0. 595 func (Implementation) Dscal(n int, alpha float64, x []float64, incX int) { 596 if incX < 1 { 597 if incX == 0 { 598 panic(zeroIncX) 599 } 600 return 601 } 602 if n < 1 { 603 if n == 0 { 604 return 605 } 606 panic(nLT0) 607 } 608 if (n-1)*incX >= len(x) { 609 panic(shortX) 610 } 611 if alpha == 0 { 612 if incX == 1 { 613 x = x[:n] 614 for i := range x { 615 x[i] = 0 616 } 617 return 618 } 619 for ix := 0; ix < n*incX; ix += incX { 620 x[ix] = 0 621 } 622 return 623 } 624 if incX == 1 { 625 f64.ScalUnitary(alpha, x[:n]) 626 return 627 } 628 f64.ScalInc(alpha, x, uintptr(n), uintptr(incX)) 629 }