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