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 5package f64 6 7import ( 8 "fmt" 9 "math" 10 "testing" 11 12 "golang.org/x/exp/rand" 13) 14 15func TestDotUnitary(t *testing.T) { 16 for i, test := range []struct { 17 xData []float64 18 yData []float64 19 20 want float64 21 }{ 22 { 23 xData: []float64{2}, 24 yData: []float64{-3}, 25 want: -6, 26 }, 27 { 28 xData: []float64{2, 3}, 29 yData: []float64{-3, 4}, 30 want: 6, 31 }, 32 { 33 xData: []float64{2, 3, -4}, 34 yData: []float64{-3, 4, 5}, 35 want: -14, 36 }, 37 { 38 xData: []float64{2, 3, -4, -5}, 39 yData: []float64{-3, 4, 5, -6}, 40 want: 16, 41 }, 42 { 43 xData: []float64{0, 2, 3, -4, -5}, 44 yData: []float64{0, -3, 4, 5, -6}, 45 want: 16, 46 }, 47 { 48 xData: []float64{0, 0, 2, 3, -4, -5}, 49 yData: []float64{0, 1, -3, 4, 5, -6}, 50 want: 16, 51 }, 52 { 53 xData: []float64{0, 0, 1, 1, 2, -3, -4}, 54 yData: []float64{0, 1, 0, 3, -4, 5, -6}, 55 want: 4, 56 }, 57 { 58 xData: []float64{0, 0, 1, 1, 2, -3, -4, 5}, 59 yData: []float64{0, 1, 0, 3, -4, 5, -6, 7}, 60 want: 39, 61 }, 62 } { 63 const msgGuard = "test %v: out-of-bounds write to %v argument\nfront guard: %v\nback guard: %v" 64 65 x, xFront, xBack := newGuardedVector(test.xData, 1) 66 y, yFront, yBack := newGuardedVector(test.yData, 1) 67 got := DotUnitary(x, y) 68 69 if !allNaN(xFront) || !allNaN(xBack) { 70 t.Errorf(msgGuard, i, "x", xFront, xBack) 71 } 72 if !allNaN(yFront) || !allNaN(yBack) { 73 t.Errorf(msgGuard, i, "y", yFront, yBack) 74 } 75 if !equalStrided(test.xData, x, 1) { 76 t.Errorf("test %v: modified read-only x argument", i) 77 } 78 if !equalStrided(test.yData, y, 1) { 79 t.Errorf("test %v: modified read-only y argument", i) 80 } 81 if math.IsNaN(got) { 82 t.Errorf("test %v: invalid memory read", i) 83 continue 84 } 85 86 if got != test.want { 87 t.Errorf("test %v: unexpected result. want %v, got %v", i, test.want, got) 88 } 89 } 90} 91 92func TestDotInc(t *testing.T) { 93 for i, test := range []struct { 94 xData []float64 95 yData []float64 96 97 want float64 98 wantRev float64 // Result when one of the vectors is reversed. 99 }{ 100 { 101 xData: []float64{2}, 102 yData: []float64{-3}, 103 want: -6, 104 wantRev: -6, 105 }, 106 { 107 xData: []float64{2, 3}, 108 yData: []float64{-3, 4}, 109 want: 6, 110 wantRev: -1, 111 }, 112 { 113 xData: []float64{2, 3, -4}, 114 yData: []float64{-3, 4, 5}, 115 want: -14, 116 wantRev: 34, 117 }, 118 { 119 xData: []float64{2, 3, -4, -5}, 120 yData: []float64{-3, 4, 5, -6}, 121 want: 16, 122 wantRev: 2, 123 }, 124 { 125 xData: []float64{0, 2, 3, -4, -5}, 126 yData: []float64{0, -3, 4, 5, -6}, 127 want: 16, 128 wantRev: 34, 129 }, 130 { 131 xData: []float64{0, 0, 2, 3, -4, -5}, 132 yData: []float64{0, 1, -3, 4, 5, -6}, 133 want: 16, 134 wantRev: -5, 135 }, 136 { 137 xData: []float64{0, 0, 1, 1, 2, -3, -4}, 138 yData: []float64{0, 1, 0, 3, -4, 5, -6}, 139 want: 4, 140 wantRev: -4, 141 }, 142 { 143 xData: []float64{0, 0, 1, 1, 2, -3, -4, 5}, 144 yData: []float64{0, 1, 0, 3, -4, 5, -6, 7}, 145 want: 39, 146 wantRev: 3, 147 }, 148 } { 149 const msgGuard = "%v: out-of-bounds write to %v argument\nfront guard: %v\nback guard: %v" 150 151 for _, incX := range []int{-7, -3, -2, -1, 1, 2, 3, 7} { 152 for _, incY := range []int{-7, -3, -2, -1, 1, 2, 3, 7} { 153 n := len(test.xData) 154 x, xFront, xBack := newGuardedVector(test.xData, incX) 155 y, yFront, yBack := newGuardedVector(test.yData, incY) 156 157 var ix, iy int 158 if incX < 0 { 159 ix = (-n + 1) * incX 160 } 161 if incY < 0 { 162 iy = (-n + 1) * incY 163 } 164 got := DotInc(x, y, uintptr(n), uintptr(incX), uintptr(incY), uintptr(ix), uintptr(iy)) 165 166 prefix := fmt.Sprintf("test %v, incX = %v, incY = %v", i, incX, incY) 167 if !allNaN(xFront) || !allNaN(xBack) { 168 t.Errorf(msgGuard, prefix, "x", xFront, xBack) 169 } 170 if !allNaN(yFront) || !allNaN(yBack) { 171 t.Errorf(msgGuard, prefix, "y", yFront, yBack) 172 } 173 if nonStridedWrite(x, incX) || !equalStrided(test.xData, x, incX) { 174 t.Errorf("%v: modified read-only x argument", prefix) 175 } 176 if nonStridedWrite(y, incY) || !equalStrided(test.yData, y, incY) { 177 t.Errorf("%v: modified read-only y argument", prefix) 178 } 179 if math.IsNaN(got) { 180 t.Errorf("%v: invalid memory read", prefix) 181 continue 182 } 183 184 want := test.want 185 if incX*incY < 0 { 186 want = test.wantRev 187 } 188 if got != want { 189 t.Errorf("%v: unexpected result. want %v, got %v", prefix, want, got) 190 } 191 } 192 } 193 } 194} 195 196func BenchmarkDotUnitaryN1(b *testing.B) { dotUnitaryBenchmark(b, 1) } 197func BenchmarkDotUnitaryN2(b *testing.B) { dotUnitaryBenchmark(b, 2) } 198func BenchmarkDotUnitaryN3(b *testing.B) { dotUnitaryBenchmark(b, 3) } 199func BenchmarkDotUnitaryN4(b *testing.B) { dotUnitaryBenchmark(b, 4) } 200func BenchmarkDotUnitaryN10(b *testing.B) { dotUnitaryBenchmark(b, 10) } 201func BenchmarkDotUnitaryN100(b *testing.B) { dotUnitaryBenchmark(b, 100) } 202func BenchmarkDotUnitaryN1000(b *testing.B) { dotUnitaryBenchmark(b, 1000) } 203func BenchmarkDotUnitaryN10000(b *testing.B) { dotUnitaryBenchmark(b, 10000) } 204func BenchmarkDotUnitaryN100000(b *testing.B) { dotUnitaryBenchmark(b, 100000) } 205 206var r float64 207 208func dotUnitaryBenchmark(b *testing.B, n int) { 209 x := make([]float64, n) 210 for i := range x { 211 x[i] = rand.Float64() 212 } 213 y := make([]float64, n) 214 for i := range y { 215 y[i] = rand.Float64() 216 } 217 b.ResetTimer() 218 for i := 0; i < b.N; i++ { 219 r = DotUnitary(x, y) 220 } 221} 222 223func BenchmarkDotIncN1Inc1(b *testing.B) { dotIncBenchmark(b, 1, 1) } 224 225func BenchmarkDotIncN2Inc1(b *testing.B) { dotIncBenchmark(b, 2, 1) } 226func BenchmarkDotIncN2Inc2(b *testing.B) { dotIncBenchmark(b, 2, 2) } 227func BenchmarkDotIncN2Inc4(b *testing.B) { dotIncBenchmark(b, 2, 4) } 228func BenchmarkDotIncN2Inc10(b *testing.B) { dotIncBenchmark(b, 2, 10) } 229 230func BenchmarkDotIncN3Inc1(b *testing.B) { dotIncBenchmark(b, 3, 1) } 231func BenchmarkDotIncN3Inc2(b *testing.B) { dotIncBenchmark(b, 3, 2) } 232func BenchmarkDotIncN3Inc4(b *testing.B) { dotIncBenchmark(b, 3, 4) } 233func BenchmarkDotIncN3Inc10(b *testing.B) { dotIncBenchmark(b, 3, 10) } 234 235func BenchmarkDotIncN4Inc1(b *testing.B) { dotIncBenchmark(b, 4, 1) } 236func BenchmarkDotIncN4Inc2(b *testing.B) { dotIncBenchmark(b, 4, 2) } 237func BenchmarkDotIncN4Inc4(b *testing.B) { dotIncBenchmark(b, 4, 4) } 238func BenchmarkDotIncN4Inc10(b *testing.B) { dotIncBenchmark(b, 4, 10) } 239 240func BenchmarkDotIncN10Inc1(b *testing.B) { dotIncBenchmark(b, 10, 1) } 241func BenchmarkDotIncN10Inc2(b *testing.B) { dotIncBenchmark(b, 10, 2) } 242func BenchmarkDotIncN10Inc4(b *testing.B) { dotIncBenchmark(b, 10, 4) } 243func BenchmarkDotIncN10Inc10(b *testing.B) { dotIncBenchmark(b, 10, 10) } 244 245func BenchmarkDotIncN1000Inc1(b *testing.B) { dotIncBenchmark(b, 1000, 1) } 246func BenchmarkDotIncN1000Inc2(b *testing.B) { dotIncBenchmark(b, 1000, 2) } 247func BenchmarkDotIncN1000Inc4(b *testing.B) { dotIncBenchmark(b, 1000, 4) } 248func BenchmarkDotIncN1000Inc10(b *testing.B) { dotIncBenchmark(b, 1000, 10) } 249 250func BenchmarkDotIncN100000Inc1(b *testing.B) { dotIncBenchmark(b, 100000, 1) } 251func BenchmarkDotIncN100000Inc2(b *testing.B) { dotIncBenchmark(b, 100000, 2) } 252func BenchmarkDotIncN100000Inc4(b *testing.B) { dotIncBenchmark(b, 100000, 4) } 253func BenchmarkDotIncN100000Inc10(b *testing.B) { dotIncBenchmark(b, 100000, 10) } 254 255func BenchmarkDotIncN100000IncM1(b *testing.B) { dotIncBenchmark(b, 100000, -1) } 256func BenchmarkDotIncN100000IncM2(b *testing.B) { dotIncBenchmark(b, 100000, -2) } 257func BenchmarkDotIncN100000IncM4(b *testing.B) { dotIncBenchmark(b, 100000, -4) } 258func BenchmarkDotIncN100000IncM10(b *testing.B) { dotIncBenchmark(b, 100000, -10) } 259 260func dotIncBenchmark(b *testing.B, n, inc int) { 261 absInc := inc 262 if inc < 0 { 263 absInc = -inc 264 } 265 x := make([]float64, (n-1)*absInc+1) 266 for i := range x { 267 x[i] = rand.Float64() 268 } 269 y := make([]float64, (n-1)*absInc+1) 270 for i := range y { 271 y[i] = rand.Float64() 272 } 273 var ini int 274 if inc < 0 { 275 ini = (-n + 1) * inc 276 } 277 b.ResetTimer() 278 for i := 0; i < b.N; i++ { 279 r = DotInc(x, y, uintptr(n), uintptr(inc), uintptr(inc), uintptr(ini), uintptr(ini)) 280 } 281} 282