// Copyright ©2015 The Gonum Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package gonum import ( "math" "gonum.org/v1/gonum/blas" "gonum.org/v1/gonum/internal/asm/f64" ) var _ blas.Float64Level1 = Implementation{} // Dnrm2 computes the Euclidean norm of a vector, // sqrt(\sum_i x[i] * x[i]). // This function returns 0 if incX is negative. func (Implementation) Dnrm2(n int, x []float64, incX int) float64 { if incX < 1 { if incX == 0 { panic(zeroIncX) } return 0 } if incX > 0 && (n-1)*incX >= len(x) { panic(badX) } if n < 2 { if n == 1 { return math.Abs(x[0]) } if n == 0 { return 0 } if n < 1 { panic(negativeN) } } var ( scale float64 = 0 sumSquares float64 = 1 ) if incX == 1 { x = x[:n] for _, v := range x { if v == 0 { continue } absxi := math.Abs(v) if math.IsNaN(absxi) { return math.NaN() } if scale < absxi { sumSquares = 1 + sumSquares*(scale/absxi)*(scale/absxi) scale = absxi } else { sumSquares = sumSquares + (absxi/scale)*(absxi/scale) } } if math.IsInf(scale, 1) { return math.Inf(1) } return scale * math.Sqrt(sumSquares) } for ix := 0; ix < n*incX; ix += incX { val := x[ix] if val == 0 { continue } absxi := math.Abs(val) if math.IsNaN(absxi) { return math.NaN() } if scale < absxi { sumSquares = 1 + sumSquares*(scale/absxi)*(scale/absxi) scale = absxi } else { sumSquares = sumSquares + (absxi/scale)*(absxi/scale) } } if math.IsInf(scale, 1) { return math.Inf(1) } return scale * math.Sqrt(sumSquares) } // Dasum computes the sum of the absolute values of the elements of x. // \sum_i |x[i]| // Dasum returns 0 if incX is negative. func (Implementation) Dasum(n int, x []float64, incX int) float64 { var sum float64 if n < 0 { panic(negativeN) } if incX < 1 { if incX == 0 { panic(zeroIncX) } return 0 } if incX > 0 && (n-1)*incX >= len(x) { panic(badX) } if incX == 1 { x = x[:n] for _, v := range x { sum += math.Abs(v) } return sum } for i := 0; i < n; i++ { sum += math.Abs(x[i*incX]) } return sum } // Idamax returns the index of an element of x with the largest absolute value. // If there are multiple such indices the earliest is returned. // Idamax returns -1 if n == 0. func (Implementation) Idamax(n int, x []float64, incX int) int { if incX < 1 { if incX == 0 { panic(zeroIncX) } return -1 } if incX > 0 && (n-1)*incX >= len(x) { panic(badX) } if n < 2 { if n == 1 { return 0 } if n == 0 { return -1 // Netlib returns invalid index when n == 0 } if n < 1 { panic(negativeN) } } idx := 0 max := math.Abs(x[0]) if incX == 1 { for i, v := range x[:n] { absV := math.Abs(v) if absV > max { max = absV idx = i } } return idx } ix := incX for i := 1; i < n; i++ { v := x[ix] absV := math.Abs(v) if absV > max { max = absV idx = i } ix += incX } return idx } // Dswap exchanges the elements of two vectors. // x[i], y[i] = y[i], x[i] for all i func (Implementation) Dswap(n int, x []float64, incX int, y []float64, incY int) { if incX == 0 { panic(zeroIncX) } if incY == 0 { panic(zeroIncY) } if n < 1 { if n == 0 { return } panic(negativeN) } if (incX > 0 && (n-1)*incX >= len(x)) || (incX < 0 && (1-n)*incX >= len(x)) { panic(badX) } if (incY > 0 && (n-1)*incY >= len(y)) || (incY < 0 && (1-n)*incY >= len(y)) { panic(badY) } if incX == 1 && incY == 1 { x = x[:n] for i, v := range x { x[i], y[i] = y[i], v } return } var ix, iy int if incX < 0 { ix = (-n + 1) * incX } if incY < 0 { iy = (-n + 1) * incY } for i := 0; i < n; i++ { x[ix], y[iy] = y[iy], x[ix] ix += incX iy += incY } } // Dcopy copies the elements of x into the elements of y. // y[i] = x[i] for all i func (Implementation) Dcopy(n int, x []float64, incX int, y []float64, incY int) { if incX == 0 { panic(zeroIncX) } if incY == 0 { panic(zeroIncY) } if n < 1 { if n == 0 { return } panic(negativeN) } if (incX > 0 && (n-1)*incX >= len(x)) || (incX < 0 && (1-n)*incX >= len(x)) { panic(badX) } if (incY > 0 && (n-1)*incY >= len(y)) || (incY < 0 && (1-n)*incY >= len(y)) { panic(badY) } if incX == 1 && incY == 1 { copy(y[:n], x[:n]) return } var ix, iy int if incX < 0 { ix = (-n + 1) * incX } if incY < 0 { iy = (-n + 1) * incY } for i := 0; i < n; i++ { y[iy] = x[ix] ix += incX iy += incY } } // Daxpy adds alpha times x to y // y[i] += alpha * x[i] for all i func (Implementation) Daxpy(n int, alpha float64, x []float64, incX int, y []float64, incY int) { if incX == 0 { panic(zeroIncX) } if incY == 0 { panic(zeroIncY) } if n < 1 { if n == 0 { return } panic(negativeN) } if (incX > 0 && (n-1)*incX >= len(x)) || (incX < 0 && (1-n)*incX >= len(x)) { panic(badX) } if (incY > 0 && (n-1)*incY >= len(y)) || (incY < 0 && (1-n)*incY >= len(y)) { panic(badY) } if alpha == 0 { return } if incX == 1 && incY == 1 { f64.AxpyUnitary(alpha, x[:n], y[:n]) return } var ix, iy int if incX < 0 { ix = (-n + 1) * incX } if incY < 0 { iy = (-n + 1) * incY } f64.AxpyInc(alpha, x, y, uintptr(n), uintptr(incX), uintptr(incY), uintptr(ix), uintptr(iy)) } // Drotg computes the plane rotation // _ _ _ _ _ _ // | c s | | a | | r | // | -s c | * | b | = | 0 | // ‾ ‾ ‾ ‾ ‾ ‾ // where // r = ±√(a^2 + b^2) // c = a/r, the cosine of the plane rotation // s = b/r, the sine of the plane rotation // // NOTE: There is a discrepancy between the refence implementation and the BLAS // technical manual regarding the sign for r when a or b are zero. // Drotg agrees with the definition in the manual and other // common BLAS implementations. func (Implementation) Drotg(a, b float64) (c, s, r, z float64) { if b == 0 && a == 0 { return 1, 0, a, 0 } absA := math.Abs(a) absB := math.Abs(b) aGTb := absA > absB r = math.Hypot(a, b) if aGTb { r = math.Copysign(r, a) } else { r = math.Copysign(r, b) } c = a / r s = b / r if aGTb { z = s } else if c != 0 { // r == 0 case handled above z = 1 / c } else { z = 1 } return } // Drotmg computes the modified Givens rotation. See // http://www.netlib.org/lapack/explore-html/df/deb/drotmg_8f.html // for more details. func (Implementation) Drotmg(d1, d2, x1, y1 float64) (p blas.DrotmParams, rd1, rd2, rx1 float64) { var p1, p2, q1, q2, u float64 const ( gam = 4096.0 gamsq = 16777216.0 rgamsq = 5.9604645e-8 ) if d1 < 0 { p.Flag = blas.Rescaling return } p2 = d2 * y1 if p2 == 0 { p.Flag = blas.Identity rd1 = d1 rd2 = d2 rx1 = x1 return } p1 = d1 * x1 q2 = p2 * y1 q1 = p1 * x1 absQ1 := math.Abs(q1) absQ2 := math.Abs(q2) if absQ1 < absQ2 && q2 < 0 { p.Flag = blas.Rescaling return } if d1 == 0 { p.Flag = blas.Diagonal p.H[0] = p1 / p2 p.H[3] = x1 / y1 u = 1 + p.H[0]*p.H[3] rd1, rd2 = d2/u, d1/u rx1 = y1 / u return } // Now we know that d1 != 0, and d2 != 0. If d2 == 0, it would be caught // when p2 == 0, and if d1 == 0, then it is caught above if absQ1 > absQ2 { p.H[1] = -y1 / x1 p.H[2] = p2 / p1 u = 1 - p.H[2]*p.H[1] rd1 = d1 rd2 = d2 rx1 = x1 p.Flag = blas.OffDiagonal // u must be greater than zero because |q1| > |q2|, so check from netlib // is unnecessary // This is left in for ease of comparison with complex routines //if u > 0 { rd1 /= u rd2 /= u rx1 *= u //} } else { p.Flag = blas.Diagonal p.H[0] = p1 / p2 p.H[3] = x1 / y1 u = 1 + p.H[0]*p.H[3] rd1 = d2 / u rd2 = d1 / u rx1 = y1 * u } for rd1 <= rgamsq || rd1 >= gamsq { if p.Flag == blas.OffDiagonal { p.H[0] = 1 p.H[3] = 1 p.Flag = blas.Rescaling } else if p.Flag == blas.Diagonal { p.H[1] = -1 p.H[2] = 1 p.Flag = blas.Rescaling } if rd1 <= rgamsq { rd1 *= gam * gam rx1 /= gam p.H[0] /= gam p.H[2] /= gam } else { rd1 /= gam * gam rx1 *= gam p.H[0] *= gam p.H[2] *= gam } } for math.Abs(rd2) <= rgamsq || math.Abs(rd2) >= gamsq { if p.Flag == blas.OffDiagonal { p.H[0] = 1 p.H[3] = 1 p.Flag = blas.Rescaling } else if p.Flag == blas.Diagonal { p.H[1] = -1 p.H[2] = 1 p.Flag = blas.Rescaling } if math.Abs(rd2) <= rgamsq { rd2 *= gam * gam p.H[1] /= gam p.H[3] /= gam } else { rd2 /= gam * gam p.H[1] *= gam p.H[3] *= gam } } return } // Drot applies a plane transformation. // x[i] = c * x[i] + s * y[i] // y[i] = c * y[i] - s * x[i] func (Implementation) Drot(n int, x []float64, incX int, y []float64, incY int, c float64, s float64) { if incX == 0 { panic(zeroIncX) } if incY == 0 { panic(zeroIncY) } if n < 1 { if n == 0 { return } panic(negativeN) } if (incX > 0 && (n-1)*incX >= len(x)) || (incX < 0 && (1-n)*incX >= len(x)) { panic(badX) } if (incY > 0 && (n-1)*incY >= len(y)) || (incY < 0 && (1-n)*incY >= len(y)) { panic(badY) } if incX == 1 && incY == 1 { x = x[:n] for i, vx := range x { vy := y[i] x[i], y[i] = c*vx+s*vy, c*vy-s*vx } return } var ix, iy int if incX < 0 { ix = (-n + 1) * incX } if incY < 0 { iy = (-n + 1) * incY } for i := 0; i < n; i++ { vx := x[ix] vy := y[iy] x[ix], y[iy] = c*vx+s*vy, c*vy-s*vx ix += incX iy += incY } } // Drotm applies the modified Givens rotation to the 2×n matrix. func (Implementation) Drotm(n int, x []float64, incX int, y []float64, incY int, p blas.DrotmParams) { if incX == 0 { panic(zeroIncX) } if incY == 0 { panic(zeroIncY) } if n <= 0 { if n == 0 { return } panic(negativeN) } if (incX > 0 && (n-1)*incX >= len(x)) || (incX < 0 && (1-n)*incX >= len(x)) { panic(badX) } if (incY > 0 && (n-1)*incY >= len(y)) || (incY < 0 && (1-n)*incY >= len(y)) { panic(badY) } var h11, h12, h21, h22 float64 var ix, iy int switch p.Flag { case blas.Identity: return case blas.Rescaling: h11 = p.H[0] h12 = p.H[2] h21 = p.H[1] h22 = p.H[3] case blas.OffDiagonal: h11 = 1 h12 = p.H[2] h21 = p.H[1] h22 = 1 case blas.Diagonal: h11 = p.H[0] h12 = 1 h21 = -1 h22 = p.H[3] } if incX < 0 { ix = (-n + 1) * incX } if incY < 0 { iy = (-n + 1) * incY } if incX == 1 && incY == 1 { x = x[:n] for i, vx := range x { vy := y[i] x[i], y[i] = vx*h11+vy*h12, vx*h21+vy*h22 } return } for i := 0; i < n; i++ { vx := x[ix] vy := y[iy] x[ix], y[iy] = vx*h11+vy*h12, vx*h21+vy*h22 ix += incX iy += incY } } // Dscal scales x by alpha. // x[i] *= alpha // Dscal has no effect if incX < 0. func (Implementation) Dscal(n int, alpha float64, x []float64, incX int) { if incX < 1 { if incX == 0 { panic(zeroIncX) } return } if (n-1)*incX >= len(x) { panic(badX) } if n < 1 { if n == 0 { return } panic(negativeN) } if alpha == 0 { if incX == 1 { x = x[:n] for i := range x { x[i] = 0 } return } for ix := 0; ix < n*incX; ix += incX { x[ix] = 0 } return } if incX == 1 { f64.ScalUnitary(alpha, x[:n]) return } f64.ScalInc(alpha, x, uintptr(n), uintptr(incX)) }