github.com/gonum/matrix@v0.0.0-20181209220409-c518dec07be9/mat64/inner_test.go (about)

     1  // Copyright ©2014 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 mat64
     6  
     7  import (
     8  	"math"
     9  	"testing"
    10  
    11  	"github.com/gonum/blas/blas64"
    12  	"github.com/gonum/blas/testblas"
    13  )
    14  
    15  func TestInner(t *testing.T) {
    16  	for i, test := range []struct {
    17  		x []float64
    18  		y []float64
    19  		m [][]float64
    20  	}{
    21  		{
    22  			x: []float64{5},
    23  			y: []float64{10},
    24  			m: [][]float64{{2}},
    25  		},
    26  		{
    27  			x: []float64{5, 6, 1},
    28  			y: []float64{10},
    29  			m: [][]float64{{2}, {-3}, {5}},
    30  		},
    31  		{
    32  			x: []float64{5},
    33  			y: []float64{10, 15},
    34  			m: [][]float64{{2, -3}},
    35  		},
    36  		{
    37  			x: []float64{1, 5},
    38  			y: []float64{10, 15},
    39  			m: [][]float64{
    40  				{2, -3},
    41  				{4, -1},
    42  			},
    43  		},
    44  		{
    45  			x: []float64{2, 3, 9},
    46  			y: []float64{8, 9},
    47  			m: [][]float64{
    48  				{2, 3},
    49  				{4, 5},
    50  				{6, 7},
    51  			},
    52  		},
    53  		{
    54  			x: []float64{2, 3},
    55  			y: []float64{8, 9, 9},
    56  			m: [][]float64{
    57  				{2, 3, 6},
    58  				{4, 5, 7},
    59  			},
    60  		},
    61  	} {
    62  		for _, inc := range []struct{ x, y int }{
    63  			{1, 1},
    64  			{1, 2},
    65  			{2, 1},
    66  			{2, 2},
    67  		} {
    68  			x := NewDense(1, len(test.x), test.x)
    69  			m := NewDense(flatten(test.m))
    70  			mWant := NewDense(flatten(test.m))
    71  			y := NewDense(len(test.y), 1, test.y)
    72  
    73  			var tmp, cell Dense
    74  			tmp.Mul(mWant, y)
    75  			cell.Mul(x, &tmp)
    76  
    77  			rm, cm := cell.Dims()
    78  			if rm != 1 {
    79  				t.Errorf("Test %d result doesn't have 1 row", i)
    80  			}
    81  			if cm != 1 {
    82  				t.Errorf("Test %d result doesn't have 1 column", i)
    83  			}
    84  
    85  			want := cell.At(0, 0)
    86  			got := Inner(makeVectorInc(inc.x, test.x), m, makeVectorInc(inc.y, test.y))
    87  			if got != want {
    88  				t.Errorf("Test %v: want %v, got %v", i, want, got)
    89  			}
    90  		}
    91  	}
    92  }
    93  
    94  func TestInnerSym(t *testing.T) {
    95  	for _, inc := range []struct{ x, y int }{
    96  		{1, 1},
    97  		{1, 2},
    98  		{2, 1},
    99  		{2, 2},
   100  	} {
   101  		n := 10
   102  		xData := make([]float64, n)
   103  		yData := make([]float64, n)
   104  		data := make([]float64, n*n)
   105  		for i := 0; i < n; i++ {
   106  			xData[i] = float64(i)
   107  			yData[i] = float64(i)
   108  			for j := i; j < n; j++ {
   109  				data[i*n+j] = float64(i*n + j)
   110  				data[j*n+i] = data[i*n+j]
   111  			}
   112  		}
   113  		x := makeVectorInc(inc.x, xData)
   114  		y := makeVectorInc(inc.y, yData)
   115  		m := NewDense(n, n, data)
   116  		ans := Inner(x, m, y)
   117  		sym := NewSymDense(n, data)
   118  		// Poison the lower half of data to ensure it is not used.
   119  		for i := 1; i < n; i++ {
   120  			for j := 0; j < i; j++ {
   121  				data[i*n+j] = math.NaN()
   122  			}
   123  		}
   124  
   125  		if math.Abs(Inner(x, sym, y)-ans) > 1e-14 {
   126  			t.Error("inner different symmetric and dense")
   127  		}
   128  	}
   129  }
   130  
   131  func makeVectorInc(inc int, f []float64) *Vector {
   132  	v := &Vector{
   133  		n: len(f),
   134  		mat: blas64.Vector{
   135  			Inc:  inc,
   136  			Data: make([]float64, (len(f)-1)*inc+1),
   137  		},
   138  	}
   139  
   140  	// Contaminate backing data in all positions...
   141  	const base = 100
   142  	for i := range v.mat.Data {
   143  		v.mat.Data[i] = float64(i + base)
   144  	}
   145  
   146  	// then write real elements.
   147  	for i := range f {
   148  		v.mat.Data[i*inc] = f[i]
   149  	}
   150  	return v
   151  }
   152  
   153  func benchmarkInner(b *testing.B, m, n int) {
   154  	x := NewVector(m, nil)
   155  	randomSlice(x.mat.Data)
   156  	y := NewVector(n, nil)
   157  	randomSlice(y.mat.Data)
   158  	data := make([]float64, m*n)
   159  	randomSlice(data)
   160  	mat := &Dense{mat: blas64.General{Rows: m, Cols: n, Stride: n, Data: data}, capRows: m, capCols: n}
   161  	b.ResetTimer()
   162  	for i := 0; i < b.N; i++ {
   163  		Inner(x, mat, y)
   164  	}
   165  }
   166  
   167  func BenchmarkInnerSmSm(b *testing.B) {
   168  	benchmarkInner(b, testblas.SmallMat, testblas.SmallMat)
   169  }
   170  
   171  func BenchmarkInnerMedMed(b *testing.B) {
   172  	benchmarkInner(b, testblas.MediumMat, testblas.MediumMat)
   173  }
   174  
   175  func BenchmarkInnerLgLg(b *testing.B) {
   176  	benchmarkInner(b, testblas.LargeMat, testblas.LargeMat)
   177  }
   178  
   179  func BenchmarkInnerLgSm(b *testing.B) {
   180  	benchmarkInner(b, testblas.LargeMat, testblas.SmallMat)
   181  }