gonum.org/v1/gonum@v0.14.0/internal/asm/c64/l2norm_test.go (about) 1 // Copyright ©2019 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 c64_test 6 7 import ( 8 "fmt" 9 "math" 10 "testing" 11 12 . "gonum.org/v1/gonum/internal/asm/c64" 13 "gonum.org/v1/gonum/internal/cmplx64" 14 "gonum.org/v1/gonum/internal/math32" 15 ) 16 17 // nanwith copied from floats package 18 func nanwith(payload uint32) complex64 { 19 const ( 20 nanBits = 0x7ff80000 21 nanMask = 0xfff80000 22 ) 23 nan := math.Float32frombits(nanBits | (payload &^ nanMask)) 24 return complex(nan, nan) 25 } 26 27 func TestL2NormUnitary(t *testing.T) { 28 const tol = 1e-7 29 30 var src_gd complex64 = 1 31 for j, v := range []struct { 32 want float32 33 x []complex64 34 }{ 35 {want: 0, x: []complex64{}}, 36 {want: 2, x: []complex64{2}}, 37 {want: 2, x: []complex64{2i}}, 38 {want: math32.Sqrt(8), x: []complex64{2 + 2i}}, 39 {want: 3.7416573867739413, x: []complex64{1, 2, 3}}, 40 {want: 3.7416573867739413, x: []complex64{-1, -2, -3}}, 41 {want: 3.7416573867739413, x: []complex64{1i, 2i, 3i}}, 42 {want: 3.7416573867739413, x: []complex64{-1i, -2i, -3i}}, 43 {want: math32.Sqrt(28), x: []complex64{1 + 1i, 2 + 2i, 3 + 3i}}, 44 {want: math32.Sqrt(28), x: []complex64{-1 - 1i, -2 - 2i, -3 - 3i}}, 45 {want: nan, x: []complex64{cnan}}, 46 {want: nan, x: []complex64{1, cinf, 3, nanwith(25), 5}}, 47 {want: 17.88854381999832, x: []complex64{8, -8, 8, -8, 8}}, 48 {want: 2.23606797749979, x: []complex64{0, 1, 0, -1, 0, 1, 0, -1, 0, 1}}, 49 {want: 17.88854381999832, x: []complex64{8i, -8i, 8i, -8i, 8i}}, 50 {want: 2.23606797749979, x: []complex64{0, 1i, 0, -1i, 0, 1i, 0, -1i, 0, 1i}}, 51 {want: math32.Sqrt(640), x: []complex64{8 + 8i, -8 - 8i, 8 + 8i, -8 - 8i, 8 + 8i}}, 52 {want: math32.Sqrt(10), x: []complex64{0, 1 + 1i, 0, -1 - 1i, 0, 1 + 1i, 0, -1 - 1i, 0, 1 + 1i}}, 53 } { 54 g_ln := 4 + j%2 55 v.x = guardVector(v.x, src_gd, g_ln) 56 src := v.x[g_ln : len(v.x)-g_ln] 57 ret := L2NormUnitary(src) 58 if !sameApprox(ret, v.want, tol) { 59 t.Errorf("Test %d L2Norm error Got: %f Expected: %f", j, ret, v.want) 60 } 61 if !isValidGuard(v.x, src_gd, g_ln) { 62 t.Errorf("Test %d Guard violated in src vector %v %v", j, v.x[:g_ln], v.x[len(v.x)-g_ln:]) 63 } 64 } 65 } 66 67 func TestL2DistanceUnitary(t *testing.T) { 68 const tol = 1e-7 69 70 var src_gd complex64 = 1 71 for j, v := range []struct { 72 want float32 73 x, y []complex64 74 }{ 75 {want: 0, x: []complex64{}, y: []complex64{}}, 76 {want: 2, x: []complex64{3}, y: []complex64{1}}, 77 {want: 2, x: []complex64{3i}, y: []complex64{1i}}, 78 {want: 3.7416573867739413, x: []complex64{2, 4, 6}, y: []complex64{1, 2, 3}}, 79 {want: 3.7416573867739413, x: []complex64{1, 2, 3}, y: []complex64{2, 4, 6}}, 80 {want: 3.7416573867739413, x: []complex64{2i, 4i, 6i}, y: []complex64{1i, 2i, 3i}}, 81 {want: 3.7416573867739413, x: []complex64{1i, 2i, 3i}, y: []complex64{2i, 4i, 6i}}, 82 {want: math32.Sqrt(28), x: []complex64{2 + 2i, 4 + 4i, 6 + 6i}, y: []complex64{1 + 1i, 2 + 2i, 3 + 3i}}, 83 {want: math32.Sqrt(28), x: []complex64{1 + 1i, 2 + 2i, 3 + 3i}, y: []complex64{2 + 2i, 4 + 4i, 6 + 6i}}, 84 {want: nan, x: []complex64{cnan}, y: []complex64{0}}, 85 {want: 17.88854381999832, x: []complex64{9, -9, 9, -9, 9}, y: []complex64{1, -1, 1, -1, 1}}, 86 {want: 2.23606797749979, x: []complex64{0, 1, 0, -1, 0, 1, 0, -1, 0, 1}, y: []complex64{0, 2, 0, -2, 0, 2, 0, -2, 0, 2}}, 87 {want: 17.88854381999832, x: []complex64{9i, -9i, 9i, -9i, 9i}, y: []complex64{1i, -1i, 1i, -1i, 1i}}, 88 {want: 2.23606797749979, x: []complex64{0, 1i, 0, -1i, 0, 1i, 0, -1i, 0, 1i}, y: []complex64{0, 2i, 0, -2i, 0, 2i, 0, -2i, 0, 2i}}, 89 {want: math32.Sqrt(640), x: []complex64{9 + 9i, -9 - 9i, 9 + 9i, -9 - 9i, 9 + 9i}, y: []complex64{1 + 1i, -1 - 1i, 1 + 1i, -1 - 1i, 1 + 1i}}, 90 {want: math32.Sqrt(10), x: []complex64{0, 1 + 1i, 0, -1 - 1i, 0, 1 + 1i, 0, -1 - 1i, 0, 1 + 1i}, y: []complex64{0, 2 + 2i, 0, -2 - 2i, 0, 2 + 2i, 0, -2 - 2i, 0, 2 + 2i}}, 91 } { 92 g_ln := 4 + j%2 93 v.x = guardVector(v.x, src_gd, g_ln) 94 v.y = guardVector(v.y, src_gd, g_ln) 95 srcX := v.x[g_ln : len(v.x)-g_ln] 96 srcY := v.y[g_ln : len(v.y)-g_ln] 97 ret := L2DistanceUnitary(srcX, srcY) 98 if !sameApprox(ret, v.want, tol) { 99 t.Errorf("Test %d L2Distance error Got: %f Expected: %f", j, ret, v.want) 100 } 101 if !isValidGuard(v.x, src_gd, g_ln) { 102 t.Errorf("Test %d Guard violated in src vector %v %v", j, v.x[:g_ln], v.x[len(v.x)-g_ln:]) 103 } 104 } 105 } 106 107 func BenchmarkL2NormNetlib(b *testing.B) { 108 netlib := func(x []complex64) (sum float32) { 109 var scale float32 110 sumSquares := float32(1.0) 111 for _, v := range x { 112 if v == 0 { 113 continue 114 } 115 absxi := cmplx64.Abs(v) 116 if math32.IsNaN(absxi) { 117 return math32.NaN() 118 } 119 if scale < absxi { 120 s := scale / absxi 121 sumSquares = 1 + sumSquares*s*s 122 scale = absxi 123 } else { 124 s := absxi / scale 125 sumSquares += s * s 126 } 127 } 128 if math32.IsInf(scale, 1) { 129 return math32.Inf(1) 130 } 131 return scale * math32.Sqrt(sumSquares) 132 } 133 134 tests := []struct { 135 name string 136 f func(x []complex64) float32 137 }{ 138 {"L2NormUnitaryNetlib", netlib}, 139 {"L2NormUnitary", L2NormUnitary}, 140 } 141 x[0] = 4 // replace the leading zero (edge case) 142 for _, test := range tests { 143 for _, ln := range []uintptr{1, 3, 10, 30, 1e2, 3e2, 1e3, 3e3, 1e4, 3e4, 1e5} { 144 b.Run(fmt.Sprintf("%s-%d", test.name, ln), func(b *testing.B) { 145 b.SetBytes(int64(64 * ln)) 146 x := x[:ln] 147 b.ResetTimer() 148 for i := 0; i < b.N; i++ { 149 test.f(x) 150 } 151 }) 152 } 153 } 154 }