github.com/jingcheng-WU/gonum@v0.9.1-0.20210323123734-f1a2a11a8f7b/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/jingcheng-WU/gonum/blas" 11 "github.com/jingcheng-WU/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 the plane rotation 241 // _ _ _ _ _ _ 242 // | c s | | a | | r | 243 // | -s c | * | b | = | 0 | 244 // ‾ ‾ ‾ ‾ ‾ ‾ 245 // where 246 // r = ±√(a^2 + b^2) 247 // c = a/r, the cosine of the plane rotation 248 // s = b/r, the sine of the plane rotation 249 // 250 // NOTE: There is a discrepancy between the reference implementation and the BLAS 251 // technical manual regarding the sign for r when a or b are zero. 252 // Drotg agrees with the definition in the manual and other 253 // common BLAS implementations. 254 func (Implementation) Drotg(a, b float64) (c, s, r, z float64) { 255 if b == 0 && a == 0 { 256 return 1, 0, a, 0 257 } 258 absA := math.Abs(a) 259 absB := math.Abs(b) 260 aGTb := absA > absB 261 r = math.Hypot(a, b) 262 if aGTb { 263 r = math.Copysign(r, a) 264 } else { 265 r = math.Copysign(r, b) 266 } 267 c = a / r 268 s = b / r 269 if aGTb { 270 z = s 271 } else if c != 0 { // r == 0 case handled above 272 z = 1 / c 273 } else { 274 z = 1 275 } 276 return 277 } 278 279 // Drotmg computes the modified Givens rotation. See 280 // http://www.netlib.org/lapack/explore-html/df/deb/drotmg_8f.html 281 // for more details. 282 func (Implementation) Drotmg(d1, d2, x1, y1 float64) (p blas.DrotmParams, rd1, rd2, rx1 float64) { 283 // The implementation of Drotmg used here is taken from Hopkins 1997 284 // Appendix A: https://doi.org/10.1145/289251.289253 285 // with the exception of the gam constants below. 286 287 const ( 288 gam = 4096.0 289 gamsq = gam * gam 290 rgamsq = 1.0 / gamsq 291 ) 292 293 if d1 < 0 { 294 p.Flag = blas.Rescaling // Error state. 295 return p, 0, 0, 0 296 } 297 298 if d2 == 0 || y1 == 0 { 299 p.Flag = blas.Identity 300 return p, d1, d2, x1 301 } 302 303 var h11, h12, h21, h22 float64 304 if (d1 == 0 || x1 == 0) && d2 > 0 { 305 p.Flag = blas.Diagonal 306 h12 = 1 307 h21 = -1 308 x1 = y1 309 d1, d2 = d2, d1 310 } else { 311 p2 := d2 * y1 312 p1 := d1 * x1 313 q2 := p2 * y1 314 q1 := p1 * x1 315 if math.Abs(q1) > math.Abs(q2) { 316 p.Flag = blas.OffDiagonal 317 h11 = 1 318 h22 = 1 319 h21 = -y1 / x1 320 h12 = p2 / p1 321 u := 1 - float64(h12*h21) 322 if u <= 0 { 323 p.Flag = blas.Rescaling // Error state. 324 return p, 0, 0, 0 325 } 326 327 d1 /= u 328 d2 /= u 329 x1 *= u 330 } else { 331 if q2 < 0 { 332 p.Flag = blas.Rescaling // Error state. 333 return p, 0, 0, 0 334 } 335 336 p.Flag = blas.Diagonal 337 h21 = -1 338 h12 = 1 339 h11 = p1 / p2 340 h22 = x1 / y1 341 u := 1 + float64(h11*h22) 342 d1, d2 = d2/u, d1/u 343 x1 = y1 * u 344 } 345 } 346 347 for d1 <= rgamsq && d1 != 0 { 348 p.Flag = blas.Rescaling 349 d1 = (d1 * gam) * gam 350 x1 /= gam 351 h11 /= gam 352 h12 /= gam 353 } 354 for d1 > gamsq { 355 p.Flag = blas.Rescaling 356 d1 = (d1 / gam) / gam 357 x1 *= gam 358 h11 *= gam 359 h12 *= gam 360 } 361 362 for math.Abs(d2) <= rgamsq && d2 != 0 { 363 p.Flag = blas.Rescaling 364 d2 = (d2 * gam) * gam 365 h21 /= gam 366 h22 /= gam 367 } 368 for math.Abs(d2) > gamsq { 369 p.Flag = blas.Rescaling 370 d2 = (d2 / gam) / gam 371 h21 *= gam 372 h22 *= gam 373 } 374 375 switch p.Flag { 376 case blas.Diagonal: 377 p.H = [4]float64{0: h11, 3: h22} 378 case blas.OffDiagonal: 379 p.H = [4]float64{1: h21, 2: h12} 380 case blas.Rescaling: 381 p.H = [4]float64{h11, h21, h12, h22} 382 default: 383 panic(badFlag) 384 } 385 386 return p, d1, d2, x1 387 } 388 389 // Drot applies a plane transformation. 390 // x[i] = c * x[i] + s * y[i] 391 // y[i] = c * y[i] - s * x[i] 392 func (Implementation) Drot(n int, x []float64, incX int, y []float64, incY int, c float64, s float64) { 393 if incX == 0 { 394 panic(zeroIncX) 395 } 396 if incY == 0 { 397 panic(zeroIncY) 398 } 399 if n < 1 { 400 if n == 0 { 401 return 402 } 403 panic(nLT0) 404 } 405 if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { 406 panic(shortX) 407 } 408 if (incY > 0 && len(y) <= (n-1)*incY) || (incY < 0 && len(y) <= (1-n)*incY) { 409 panic(shortY) 410 } 411 if incX == 1 && incY == 1 { 412 x = x[:n] 413 for i, vx := range x { 414 vy := y[i] 415 x[i], y[i] = c*vx+s*vy, c*vy-s*vx 416 } 417 return 418 } 419 var ix, iy int 420 if incX < 0 { 421 ix = (-n + 1) * incX 422 } 423 if incY < 0 { 424 iy = (-n + 1) * incY 425 } 426 for i := 0; i < n; i++ { 427 vx := x[ix] 428 vy := y[iy] 429 x[ix], y[iy] = c*vx+s*vy, c*vy-s*vx 430 ix += incX 431 iy += incY 432 } 433 } 434 435 // Drotm applies the modified Givens rotation to the 2×n matrix. 436 func (Implementation) Drotm(n int, x []float64, incX int, y []float64, incY int, p blas.DrotmParams) { 437 if incX == 0 { 438 panic(zeroIncX) 439 } 440 if incY == 0 { 441 panic(zeroIncY) 442 } 443 if n <= 0 { 444 if n == 0 { 445 return 446 } 447 panic(nLT0) 448 } 449 if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) { 450 panic(shortX) 451 } 452 if (incY > 0 && len(y) <= (n-1)*incY) || (incY < 0 && len(y) <= (1-n)*incY) { 453 panic(shortY) 454 } 455 456 if p.Flag == blas.Identity { 457 return 458 } 459 460 switch p.Flag { 461 case blas.Rescaling: 462 h11 := p.H[0] 463 h12 := p.H[2] 464 h21 := p.H[1] 465 h22 := p.H[3] 466 if incX == 1 && incY == 1 { 467 x = x[:n] 468 for i, vx := range x { 469 vy := y[i] 470 x[i], y[i] = float64(vx*h11)+float64(vy*h12), float64(vx*h21)+float64(vy*h22) 471 } 472 return 473 } 474 var ix, iy int 475 if incX < 0 { 476 ix = (-n + 1) * incX 477 } 478 if incY < 0 { 479 iy = (-n + 1) * incY 480 } 481 for i := 0; i < n; i++ { 482 vx := x[ix] 483 vy := y[iy] 484 x[ix], y[iy] = float64(vx*h11)+float64(vy*h12), float64(vx*h21)+float64(vy*h22) 485 ix += incX 486 iy += incY 487 } 488 case blas.OffDiagonal: 489 h12 := p.H[2] 490 h21 := p.H[1] 491 if incX == 1 && incY == 1 { 492 x = x[:n] 493 for i, vx := range x { 494 vy := y[i] 495 x[i], y[i] = vx+float64(vy*h12), float64(vx*h21)+vy 496 } 497 return 498 } 499 var ix, iy int 500 if incX < 0 { 501 ix = (-n + 1) * incX 502 } 503 if incY < 0 { 504 iy = (-n + 1) * incY 505 } 506 for i := 0; i < n; i++ { 507 vx := x[ix] 508 vy := y[iy] 509 x[ix], y[iy] = vx+float64(vy*h12), float64(vx*h21)+vy 510 ix += incX 511 iy += incY 512 } 513 case blas.Diagonal: 514 h11 := p.H[0] 515 h22 := p.H[3] 516 if incX == 1 && incY == 1 { 517 x = x[:n] 518 for i, vx := range x { 519 vy := y[i] 520 x[i], y[i] = float64(vx*h11)+vy, -vx+float64(vy*h22) 521 } 522 return 523 } 524 var ix, iy int 525 if incX < 0 { 526 ix = (-n + 1) * incX 527 } 528 if incY < 0 { 529 iy = (-n + 1) * incY 530 } 531 for i := 0; i < n; i++ { 532 vx := x[ix] 533 vy := y[iy] 534 x[ix], y[iy] = float64(vx*h11)+vy, -vx+float64(vy*h22) 535 ix += incX 536 iy += incY 537 } 538 } 539 } 540 541 // Dscal scales x by alpha. 542 // x[i] *= alpha 543 // Dscal has no effect if incX < 0. 544 func (Implementation) Dscal(n int, alpha float64, x []float64, incX int) { 545 if incX < 1 { 546 if incX == 0 { 547 panic(zeroIncX) 548 } 549 return 550 } 551 if n < 1 { 552 if n == 0 { 553 return 554 } 555 panic(nLT0) 556 } 557 if (n-1)*incX >= len(x) { 558 panic(shortX) 559 } 560 if alpha == 0 { 561 if incX == 1 { 562 x = x[:n] 563 for i := range x { 564 x[i] = 0 565 } 566 return 567 } 568 for ix := 0; ix < n*incX; ix += incX { 569 x[ix] = 0 570 } 571 return 572 } 573 if incX == 1 { 574 f64.ScalUnitary(alpha, x[:n]) 575 return 576 } 577 f64.ScalInc(alpha, x, uintptr(n), uintptr(incX)) 578 }