github.com/gopherd/gonum@v0.0.4/internal/asm/f64/asm_test.go (about) 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 5 package f64_test 6 7 import ( 8 "math" 9 "testing" 10 11 "math/rand" 12 13 "github.com/gopherd/gonum/floats/scalar" 14 ) 15 16 const ( 17 msgVal = "%v: unexpected value at %v Got: %v Expected: %v" 18 msgGuard = "%v: Guard violated in %s vector %v %v" 19 msgReadOnly = "%v: modified read-only %v argument" 20 ) 21 22 var ( 23 nan = math.NaN() 24 inf = math.Inf(1) 25 ) 26 27 // newGuardedVector allocates a new slice and returns it as three subslices. 28 // v is a strided vector that contains elements of data at indices i*inc and 29 // NaN elsewhere. frontGuard and backGuard are filled with NaN values, and 30 // their backing arrays are directly adjacent to v in memory. The three slices 31 // can be used to detect invalid memory reads and writes. 32 func newGuardedVector(data []float64, inc int) (v, frontGuard, backGuard []float64) { 33 if inc < 0 { 34 inc = -inc 35 } 36 guard := 2 * inc 37 size := (len(data)-1)*inc + 1 38 whole := make([]float64, size+2*guard) 39 v = whole[guard : len(whole)-guard] 40 for i := range whole { 41 whole[i] = math.NaN() 42 } 43 for i, d := range data { 44 v[i*inc] = d 45 } 46 return v, whole[:guard], whole[len(whole)-guard:] 47 } 48 49 // allNaN returns true if x contains only NaN values, and false otherwise. 50 func allNaN(x []float64) bool { 51 for _, v := range x { 52 if !math.IsNaN(v) { 53 return false 54 } 55 } 56 return true 57 } 58 59 // equalStrided returns true if the strided vector x contains elements of the 60 // dense vector ref at indices i*inc, false otherwise. 61 func equalStrided(ref, x []float64, inc int) bool { 62 if inc < 0 { 63 inc = -inc 64 } 65 for i, v := range ref { 66 if !scalar.Same(x[i*inc], v) { 67 return false 68 } 69 } 70 return true 71 } 72 73 // nonStridedWrite returns false if all elements of x at non-stride indices are 74 // equal to NaN, true otherwise. 75 func nonStridedWrite(x []float64, inc int) bool { 76 if inc < 0 { 77 inc = -inc 78 } 79 for i, v := range x { 80 if i%inc != 0 && !math.IsNaN(v) { 81 return true 82 } 83 } 84 return false 85 } 86 87 // guardVector copies the source vector (vec) into a new slice with guards. 88 // Guards guarded[:gdLn] and guarded[len-gdLn:] will be filled with sigil value gdVal. 89 func guardVector(vec []float64, gdVal float64, gdLn int) (guarded []float64) { 90 guarded = make([]float64, len(vec)+gdLn*2) 91 copy(guarded[gdLn:], vec) 92 for i := 0; i < gdLn; i++ { 93 guarded[i] = gdVal 94 guarded[len(guarded)-1-i] = gdVal 95 } 96 return guarded 97 } 98 99 // isValidGuard will test for violated guards, generated by guardVector. 100 func isValidGuard(vec []float64, gdVal float64, gdLn int) bool { 101 for i := 0; i < gdLn; i++ { 102 if !scalar.Same(vec[i], gdVal) || !scalar.Same(vec[len(vec)-1-i], gdVal) { 103 return false 104 } 105 } 106 return true 107 } 108 109 // guardIncVector copies the source vector (vec) into a new incremented slice with guards. 110 // End guards will be length gdLen. 111 // Internal and end guards will be filled with sigil value gdVal. 112 func guardIncVector(vec []float64, gdVal float64, inc, gdLen int) (guarded []float64) { 113 if inc < 0 { 114 inc = -inc 115 } 116 inrLen := len(vec) * inc 117 guarded = make([]float64, inrLen+gdLen*2) 118 for i := range guarded { 119 guarded[i] = gdVal 120 } 121 for i, v := range vec { 122 guarded[gdLen+i*inc] = v 123 } 124 return guarded 125 } 126 127 // checkValidIncGuard will test for violated guards, generated by guardIncVector 128 func checkValidIncGuard(t *testing.T, vec []float64, gdVal float64, inc, gdLen int) { 129 srcLn := len(vec) - 2*gdLen 130 for i := range vec { 131 switch { 132 case scalar.Same(vec[i], gdVal): 133 // Correct value 134 case (i-gdLen)%inc == 0 && (i-gdLen)/inc < len(vec): 135 // Ignore input values 136 case i < gdLen: 137 t.Errorf("Front guard violated at %d %v", i, vec[:gdLen]) 138 case i > gdLen+srcLn: 139 t.Errorf("Back guard violated at %d %v", i-gdLen-srcLn, vec[gdLen+srcLn:]) 140 default: 141 t.Errorf("Internal guard violated at %d %v", i-gdLen, vec[gdLen:gdLen+srcLn]) 142 } 143 } 144 } 145 146 // sameApprox tests for nan-aware equality within tolerance. 147 func sameApprox(a, b, tol float64) bool { 148 return scalar.Same(a, b) || scalar.EqualWithinAbsOrRel(a, b, tol, tol) 149 } 150 151 var ( // Offset sets for testing alignment handling in Unitary assembly functions. 152 align1 = []int{0, 1} 153 align2 = newIncSet(0, 1) 154 align3 = newIncToSet(0, 1) 155 ) 156 157 type incSet struct { 158 x, y int 159 } 160 161 // genInc will generate all (x,y) combinations of the input increment set. 162 func newIncSet(inc ...int) []incSet { 163 n := len(inc) 164 is := make([]incSet, n*n) 165 for x := range inc { 166 for y := range inc { 167 is[x*n+y] = incSet{inc[x], inc[y]} 168 } 169 } 170 return is 171 } 172 173 type incToSet struct { 174 dst, x, y int 175 } 176 177 // genIncTo will generate all (dst,x,y) combinations of the input increment set. 178 func newIncToSet(inc ...int) []incToSet { 179 n := len(inc) 180 is := make([]incToSet, n*n*n) 181 for i, dst := range inc { 182 for x := range inc { 183 for y := range inc { 184 is[i*n*n+x*n+y] = incToSet{dst, inc[x], inc[y]} 185 } 186 } 187 } 188 return is 189 } 190 191 var benchSink []float64 192 193 func randomSlice(n, inc int) []float64 { 194 if inc < 0 { 195 inc = -inc 196 } 197 x := make([]float64, (n-1)*inc+1) 198 for i := range x { 199 x[i] = rand.Float64() 200 } 201 return x 202 } 203 204 func randSlice(n, inc int, r *rand.Rand) []float64 { 205 if inc < 0 { 206 inc = -inc 207 } 208 x := make([]float64, (n-1)*inc+1) 209 for i := range x { 210 x[i] = r.Float64() 211 } 212 return x 213 }