gonum.org/v1/gonum@v0.14.0/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  	"golang.org/x/exp/rand"
    12  
    13  	"gonum.org/v1/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  }