Files
gonum/referenceblas/level1double.go
2014-01-06 15:26:37 -08:00

577 lines
10 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Uses the netlib standard. Other implementations may differ. Difference
// is that the code panics for n < 0 and incx == 0 rather than returning zero.
// (Documentation says incx must not be zero)
//
// TODO: Improve documentation
package naivegoblas
import (
"github.com/gonum/blas"
"math"
"fmt"
)
var _ = fmt.Println
type Blas struct{}
var negativeN = "blas: negative number of elements"
var zeroInc = "blas: zero value of increment"
var negInc = "blas: negative value of increment"
// Ddot computes the dot product of the two vectors \sum_i x[i]*y[i]
func (Blas) Ddot(n int, x []float64, incX int, y []float64, incY int) float64 {
if n < 0 {
panic(negativeN)
}
if incX == 0 || incY == 0 {
panic(zeroInc)
}
var ix, iy int
var sum float64
if incX < 0 {
ix = (-n + 1) * incX
}
if incY < 0 {
iy = (-n + 1) * incY
}
for i := 0; i < n; i++ {
sum += y[iy] * x[ix]
ix += incX
iy += incY
}
return sum
}
// Dnrm2 computes the euclidean norm of a vector via the function
// name so that
// dnrm2 = sqrt(x'x)
// This function also does not allow negative increments, see:
// http://www.netlib.org/blas/dnrm2.f
func (Blas) Dnrm2(n int, x []float64, incX int) float64 {
if incX < 1 {
if incX == 0 {
panic(zeroInc)
}
panic(negInc)
}
if n < 2 {
if n == 1 {
return math.Abs(x[0])
}
if n == 0 {
return 0
}
if n < 1 {
panic(negativeN)
}
}
scale := 0.0
sumSquares := 1.0
for ix := 0; ix < n*incX; ix += incX {
val := x[ix]
if val == 0 {
continue
}
absxi := math.Abs(x[ix])
if scale < absxi {
sumSquares = 1 + sumSquares*(scale/absxi)*(scale/absxi)
scale = absxi
} else {
sumSquares = sumSquares + (absxi/scale)*(absxi/scale)
}
}
return scale * math.Sqrt(sumSquares)
}
// Dasum computes the sum of the absolute values of the elements of x
// Dasum returns for negative increment in the netlib package (seems
// to differ from behavior of other routines) and so it panics here
func (Blas) Dasum(n int, x []float64, incX int) float64 {
var sum float64
if n < 0 {
panic(negativeN)
}
if incX == 0 {
panic(zeroInc)
}
if incX < 0 {
panic(negInc)
}
for i := 0; i < n; i++ {
sum += math.Abs(x[i*incX])
}
return sum
}
// Idamax returns the index of the largest element of x. If there are multiple
// such indices it returns the earliest
func (Blas) Idamax(n int, x []float64, incX int) int {
if incX < 1 {
if incX == 0 {
panic(zeroInc)
}
panic(negInc)
}
if n < 2 {
if n == 1 {
return 0
}
if n == 0 {
return 0 // Netlib returns first index when n == 0
}
if n < 1 {
panic(negativeN)
}
}
idx := 0
max := x[0]
for i := 1; i < n; i++ {
v := x[i*incX]
if v > max {
max = v
idx = i * incX
}
}
return idx
}
// Dswap interchanges two vectors
func (Blas) Dswap(n int, x []float64, incX int, y []float64, incY int) {
if n < 1 {
if n == 0 {
return
}
panic(negativeN)
}
if incX == 0 || incY == 0 {
panic(zeroInc)
}
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
}
}
func (Blas) Dcopy(n int, x []float64, incX int, y []float64, incY int) {
if n < 1 {
if n == 0 {
return
}
panic(negativeN)
}
if incX == 0 || incY == 0 {
panic(zeroInc)
}
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 computes y <- α x + y
func (Blas) Daxpy(n int, alpha float64, x []float64, incX int, y []float64, incY int) {
if n < 1 {
if n == 0 {
return
}
panic(negativeN)
}
if incX == 0 || incY == 0 {
panic(zeroInc)
}
if alpha == 0 {
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] += alpha * x[ix]
ix += incX
iy += incY
}
}
// DrotG gives plane rotation
//
// _ _ _ _ _ _
// | c s | | a | | r |
// | -s c | * | b | = | 0 |
// _ _ _ _ _ _
//
// r = ±(a^2 + b^2)
// c = a/r, the cosine of the plane rotation
// s = b/r, the sine of the plane rotation
//
// NOTE: Netlib library seems to give a different
// sign for r when a or b is zero than other implementations
// and different than BLAS technical manual
func (Blas) Drotg(a, b float64) (c, s, r, z float64) {
if b == 0 && a == 0 {
return 1, 0, a, 0
}
/*
if a == 0 {
if b > 0 {
return 0, 1, b, 1
}
return 0, -1, -b, 1
}
*/
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 (Blas) Drotmg(d1, d2, x1, y1 float64) (p blas.DrotmParams, rd1, rd2, rx1 float64) {
var p1, p2, q1, q2, u float64
gam := 4096.0
gamsq := 16777216.0
rgamsq := 5.9604645e-8
p = blas.DrotmParams{}
if d1 < 0 {
p.Flag = -1
return
}
p2 = d2 * y1
if p2 == 0 {
p.Flag = -2
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 = -1
return
}
if d1 == 0 {
p.Flag = 1
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
//fmt.Println("absq1", absQ1)
//fmt.Println("absq2", absQ2)
if math.Abs(q1) > math.Abs(q2) {
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 = 0
// 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 = 1
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
}
fmt.Println("Flag = ", p.Flag)
fmt.Println("rd1 = ", rd1)
for rd1 <= rgamsq || rd1 >= gamsq {
if p.Flag == 0 {
p.H[0] = 1
p.H[3] = 1
p.Flag = -1
} else {
p.H[1] = -1
p.H[2] = 1
p.Flag = -1
}
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
}
}
fmt.Println("rd2 = ", rd2)
for math.Abs(rd2) <= rgamsq || math.Abs(rd2) >= gamsq {
if p.Flag == 0 {
p.H[0] = 1
p.H[3] = 1
p.Flag = -1
} else {
p.H[1] = -1
p.H[2] = 1
p.Flag = -1
}
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
func (Blas) Drot(n int, x []float64, incX int, y []float64, incY int, c float64, s float64) {
if n < 1 {
if n == 0 {
return
}
panic(negativeN)
}
if incX == 0 || incY == 0 {
panic(zeroInc)
}
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] = c*x[ix]+s*y[iy], c*y[iy]-s*x[ix]
ix += incX
iy += incY
}
}
// Drotm applies the modified Givens rotation to the 2 x N matrix
func (Blas) Drotm(n int, x []float64, incX int, y []float64, incY int, p blas.DrotmParams) {
// Some weirdness between this and drotmg. Maybe drotmg should panic on flag of -2?
// Need to check if it's used elsewhere
//
// Same with some terms being zero
//
// Odd that this doesn't panic with incX == 0 or incY == 0 like all the others
if n <= 0 {
if n == 0 {
return
}
panic(negativeN)
}
if incX == 0 || incY == 0 {
panic(zeroInc)
}
var h11, h12, h21, h22 float64
var ix, iy int
switch p.Flag {
case -2:
return
case -1:
h11 = p.H[0]
h12 = p.H[2]
h21 = p.H[1]
h22 = p.H[3]
case 0:
h11 = 1
h12 = p.H[2]
h21 = p.H[1]
h22 = 1
case 1:
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
}
for i := 0; i < n; i++ {
x[ix], y[iy] = x[ix]*h11+y[iy]*h12, x[ix]*h21+y[iy]*h22
ix += incX
iy += incY
}
/*
More complicated version of the above, though possibly faster
if flag == -2 {
return
}
if incX == incY && incX > 0 {
nsteps := n * incX
if flag < 0 {
h11 := p.H[0]
h12 := p.H[2]
h21 := p.H[1]
h22 := p.H[3]
for i := 0; i < nsteps; i += incX {
w := x[i]
z := y[i]
x[i] = w*h11 + z*h12
y[i] = w*h21 + z*h22
}
return
}
if flag == 0 {
h12 := p.H[2]
h21 := p.H[1]
for i := 0; i < nsteps; i += incX {
w := x[i]
z := y[i]
x[i] = w + z*h12
y[i] = w*h21 + z
}
return
}
h11 := p.H[0]
h22 := p.H[3]
for i := 0; i < nsteps; i += incX {
w := x[i]
z := y[i]
x[i] = w*h11 + z
y[i] = -w + h22*z
}
return
}
ix := 0
iy := 0
if incX < 0 {
ix = (-n + 1) * incX
}
if incY < 0 {
iy = (-n + 1) * incY
}
if flag < 0 {
h11 := p.H[0]
h12 := p.H[2]
h21 := p.H[1]
h22 := p.H[3]
for i := 0; i < n; i++ {
w := x[ix]
z := y[iy]
x[ix] = w*h11 + z*h12
y[iy] = w*h21 + z*h22
ix += incX
iy += incY
}
return
}
if flag == 0 {
h12 := p.H[2]
h21 := p.H[1]
for i := 0; i < n; i++ {
w := x[ix]
z := y[iy]
x[ix] = w + z*h12
y[iy] = w*h21 + z
ix += incX
iy += incY
}
return
}
h11 := p.H[0]
h22 := p.H[3]
for i := 0; i < n; i++ {
w := x[ix]
z := y[iy]
x[ix] = w*h11 + z
y[iy] = -w + z*h22
ix += incX
iy += incY
}
*/
return
}
func (Blas) Dscal(n int, alpha float64, x []float64, incX int) {
if incX < 1 {
if incX == 0 {
panic(zeroInc)
}
panic(negInc)
}
if n < 1 {
if n == 0 {
return
}
if n < 1 {
panic(negativeN)
}
}
for ix := 0; ix < n*incX; ix += incX {
x[ix] *= alpha
}
return
}