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 }