asm/f64: add asm implementation of l2distance function
L2 Distance kernel is a slight modification of the L2 Norm kernel,
taking two vectors and calculating the difference before summing squares.
Same overflow protections as the netlib form of the norm calculation.
MODIFY
internal/asm/f64/l2norm_noasm.go
internal/asm/f64/l2norm_noasm.go
@@ -9,7 +9,7 @@ package f64
import "math"
// L2NormUnitary returns the L2-norm of x.
-func L2NormUnitary(x []float64) (sum float64) {
+func L2NormUnitary(x []float64) (norm float64) {
var scale float64
sumSquares := 1.0
for _, v := range x {
@@ -36,7 +36,7 @@ func L2NormUnitary(x []float64) (sum float64) {
}
// L2NormInc returns the L2-norm of x.
-func L2NormInc(x []float64, n, incX uintptr) (sum float64) {
+func L2NormInc(x []float64, n, incX uintptr) (norm float64) {
var scale float64
sumSquares := 1.0
for ix := uintptr(0); ix < n*incX; ix += incX {
@@ -62,3 +62,31 @@ func L2NormInc(x []float64, n, incX uintptr) (sum float64) {
}
return scale * math.Sqrt(sumSquares)
}
+
+// L2DistanceUnitary returns the L2-norm of x-y.
+func L2DistanceUnitary(x, y []float64) (norm float64) {
+ var scale float64
+ sumSquares := 1.0
+ for i, v := range x {
+ v -= y[i]
+ if v == 0 {
+ continue
+ }
+ absxi := math.Abs(v)
+ if math.IsNaN(absxi) {
+ return math.NaN()
+ }
+ if scale < absxi {
+ s := scale / absxi
+ sumSquares = 1 + sumSquares*s*s
+ scale = absxi
+ } else {
+ s := absxi / scale
+ sumSquares += s * s
+ }
+ }
+ if math.IsInf(scale, 1) {
+ return math.Inf(1)
+ }
+ return scale * math.Sqrt(sumSquares)
+}

MODIFY
internal/asm/f64/stubs_amd64.go
internal/asm/f64/stubs_amd64.go
@@ -195,10 +195,9 @@ func Sum(x []float64) float64
// }
// }
// return scale * math.Sqrt(sumSquares)
-func L2NormUnitary(x []float64) (sum float64)
+func L2NormUnitary(x []float64) (norm float64)
// L2NormInc returns the L2-norm of x.
-// func L2NormInc(x []float64, n, incX uintptr) (sum float64) {
// var scale float64
// sumSquares := 1.0
// for ix := uintptr(0); ix < n*incX; ix += incX {
@@ -223,5 +222,31 @@ func L2NormUnitary(x []float64) (sum float64)
// return math.Inf(1)
// }
// return scale * math.Sqrt(sumSquares)
+func L2NormInc(x []float64, n, incX uintptr) (norm float64)
+
+// L2DistanceUnitary returns the L2-norm of x-y.
+// var scale float64
+// sumSquares := 1.0
+// for i, v := range x {
+// v -= y[i]
+// if v == 0 {
+// continue
// }
-func L2NormInc(x []float64, n, incX uintptr) (sum float64)
+// absxi := math.Abs(v)
+// if math.IsNaN(absxi) {
+// return math.NaN()
+// }
+// if scale < absxi {
+// s := scale / absxi
+// sumSquares = 1 + sumSquares*s*s
+// scale = absxi
+// } else {
+// s := absxi / scale
+// sumSquares += s * s
+// }
+// }
+// if math.IsInf(scale, 1) {
+// return math.Inf(1)
+// }
+// return scale * math.Sqrt(sumSquares)
+func L2DistanceUnitary(x, y []float64) (norm float64)

asm/f64: add asm implementation of l2distance function

L2 Distance kernel is a slight modification of the L2 Norm kernel,
taking two vectors and calculating the difference before summing squares.

Same overflow protections as the netlib form of the norm calculation.