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