mirror of
https://github.com/gonum/gonum.git
synced 2025-10-05 15:16:59 +08:00
187 lines
3.7 KiB
Go
187 lines
3.7 KiB
Go
// Copyright ©2014 The Gonum Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package mat
|
|
|
|
import (
|
|
"math"
|
|
"testing"
|
|
|
|
"golang.org/x/exp/rand"
|
|
|
|
"gonum.org/v1/gonum/blas/blas64"
|
|
"gonum.org/v1/gonum/blas/testblas"
|
|
)
|
|
|
|
func TestInner(t *testing.T) {
|
|
t.Parallel()
|
|
for i, test := range []struct {
|
|
x []float64
|
|
y []float64
|
|
m [][]float64
|
|
}{
|
|
{
|
|
x: []float64{5},
|
|
y: []float64{10},
|
|
m: [][]float64{{2}},
|
|
},
|
|
{
|
|
x: []float64{5, 6, 1},
|
|
y: []float64{10},
|
|
m: [][]float64{{2}, {-3}, {5}},
|
|
},
|
|
{
|
|
x: []float64{5},
|
|
y: []float64{10, 15},
|
|
m: [][]float64{{2, -3}},
|
|
},
|
|
{
|
|
x: []float64{1, 5},
|
|
y: []float64{10, 15},
|
|
m: [][]float64{
|
|
{2, -3},
|
|
{4, -1},
|
|
},
|
|
},
|
|
{
|
|
x: []float64{2, 3, 9},
|
|
y: []float64{8, 9},
|
|
m: [][]float64{
|
|
{2, 3},
|
|
{4, 5},
|
|
{6, 7},
|
|
},
|
|
},
|
|
{
|
|
x: []float64{2, 3},
|
|
y: []float64{8, 9, 9},
|
|
m: [][]float64{
|
|
{2, 3, 6},
|
|
{4, 5, 7},
|
|
},
|
|
},
|
|
} {
|
|
for _, inc := range []struct{ x, y int }{
|
|
{1, 1},
|
|
{1, 2},
|
|
{2, 1},
|
|
{2, 2},
|
|
} {
|
|
x := NewDense(1, len(test.x), test.x)
|
|
m := NewDense(flatten(test.m))
|
|
mWant := NewDense(flatten(test.m))
|
|
y := NewDense(len(test.y), 1, test.y)
|
|
|
|
var tmp, cell Dense
|
|
tmp.Mul(mWant, y)
|
|
cell.Mul(x, &tmp)
|
|
|
|
rm, cm := cell.Dims()
|
|
if rm != 1 {
|
|
t.Errorf("Test %d result doesn't have 1 row", i)
|
|
}
|
|
if cm != 1 {
|
|
t.Errorf("Test %d result doesn't have 1 column", i)
|
|
}
|
|
|
|
want := cell.At(0, 0)
|
|
got := Inner(makeVecDenseInc(inc.x, test.x), m, makeVecDenseInc(inc.y, test.y))
|
|
if got != want {
|
|
t.Errorf("Test %v: want %v, got %v", i, want, got)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestInnerSym(t *testing.T) {
|
|
t.Parallel()
|
|
for _, inc := range []struct{ x, y int }{
|
|
{1, 1},
|
|
{1, 2},
|
|
{2, 1},
|
|
{2, 2},
|
|
} {
|
|
n := 10
|
|
xData := make([]float64, n)
|
|
yData := make([]float64, n)
|
|
data := make([]float64, n*n)
|
|
for i := 0; i < n; i++ {
|
|
xData[i] = float64(i)
|
|
yData[i] = float64(i)
|
|
for j := i; j < n; j++ {
|
|
data[i*n+j] = float64(i*n + j)
|
|
data[j*n+i] = data[i*n+j]
|
|
}
|
|
}
|
|
x := makeVecDenseInc(inc.x, xData)
|
|
y := makeVecDenseInc(inc.y, yData)
|
|
m := NewDense(n, n, data)
|
|
ans := Inner(x, m, y)
|
|
sym := NewSymDense(n, data)
|
|
// Poison the lower half of data to ensure it is not used.
|
|
for i := 1; i < n; i++ {
|
|
for j := 0; j < i; j++ {
|
|
data[i*n+j] = math.NaN()
|
|
}
|
|
}
|
|
|
|
if math.Abs(Inner(x, sym, y)-ans) > 1e-14 {
|
|
t.Error("inner different symmetric and dense")
|
|
}
|
|
}
|
|
}
|
|
|
|
func makeVecDenseInc(inc int, f []float64) *VecDense {
|
|
v := &VecDense{
|
|
mat: blas64.Vector{
|
|
N: len(f),
|
|
Inc: inc,
|
|
Data: make([]float64, (len(f)-1)*inc+1),
|
|
},
|
|
}
|
|
|
|
// Contaminate backing data in all positions...
|
|
const base = 100
|
|
for i := range v.mat.Data {
|
|
v.mat.Data[i] = float64(i + base)
|
|
}
|
|
|
|
// then write real elements.
|
|
for i := range f {
|
|
v.mat.Data[i*inc] = f[i]
|
|
}
|
|
return v
|
|
}
|
|
|
|
func benchmarkInner(b *testing.B, m, n int) {
|
|
src := rand.NewSource(1)
|
|
x := NewVecDense(m, nil)
|
|
randomSlice(x.mat.Data, src)
|
|
y := NewVecDense(n, nil)
|
|
randomSlice(y.mat.Data, src)
|
|
data := make([]float64, m*n)
|
|
randomSlice(data, src)
|
|
mat := &Dense{mat: blas64.General{Rows: m, Cols: n, Stride: n, Data: data}, capRows: m, capCols: n}
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
Inner(x, mat, y)
|
|
}
|
|
}
|
|
|
|
func BenchmarkInnerSmSm(b *testing.B) {
|
|
benchmarkInner(b, testblas.SmallMat, testblas.SmallMat)
|
|
}
|
|
|
|
func BenchmarkInnerMedMed(b *testing.B) {
|
|
benchmarkInner(b, testblas.MediumMat, testblas.MediumMat)
|
|
}
|
|
|
|
func BenchmarkInnerLgLg(b *testing.B) {
|
|
benchmarkInner(b, testblas.LargeMat, testblas.LargeMat)
|
|
}
|
|
|
|
func BenchmarkInnerLgSm(b *testing.B) {
|
|
benchmarkInner(b, testblas.LargeMat, testblas.SmallMat)
|
|
}
|