blob: bd4929b0f0ac523953b9fc09984d6e230688b0ee [file] [log] [blame]
package vec32
import (
"math"
"testing"
"github.com/stretchr/testify/assert"
"go.skia.org/infra/go/testutils/unittest"
)
const (
e = MISSING_DATA_SENTINEL
)
func near(a, b float32) bool {
return math.Abs(float64(a-b)) < 0.001
}
func vecNear(a, b []float32) bool {
if len(a) != len(b) {
return false
}
for i, x := range a {
if !near(x, b[i]) {
return false
}
}
return true
}
func TestNew(t *testing.T) {
unittest.SmallTest(t)
v := New(0)
assert.Len(t, v, 0)
v = New(1)
assert.Len(t, v, 1)
assert.Equal(t, MISSING_DATA_SENTINEL, v[0])
v = New(2)
assert.Len(t, v, 2)
assert.Equal(t, MISSING_DATA_SENTINEL, v[0])
assert.Equal(t, MISSING_DATA_SENTINEL, v[1])
}
func TestNorm(t *testing.T) {
unittest.SmallTest(t)
testCases := []struct {
In []float32
Out []float32
}{
{
In: []float32{1.0, -1.0, e},
Out: []float32{1.0, -1.0, e},
},
{
In: []float32{e, 2.0, -2.0},
Out: []float32{e, 1.0, -1.0},
},
{
In: []float32{e},
Out: []float32{e},
},
{
In: []float32{},
Out: []float32{},
},
{
In: []float32{2.0},
Out: []float32{0.0},
},
{
In: []float32{0.0, 0.1},
Out: []float32{-0.05, 0.05},
},
}
for _, tc := range testCases {
Norm(tc.In, 0.1)
if got, want := tc.In, tc.Out; !vecNear(tc.Out, tc.In) {
t.Errorf("Norm: Got %#v Want %#v", got, want)
}
}
}
func TestFill(t *testing.T) {
unittest.SmallTest(t)
testCases := []struct {
In []float32
Out []float32
}{
{
In: []float32{e, e, 2, 3, e, 5},
Out: []float32{2, 2, 2, 3, 5, 5},
},
{
In: []float32{e, 3, e},
Out: []float32{3, 3, 3},
},
{
In: []float32{e, e},
Out: []float32{0, 0},
},
{
In: []float32{e},
Out: []float32{0},
},
{
In: []float32{},
Out: []float32{},
},
}
for _, tc := range testCases {
Fill(tc.In)
if got, want := tc.In, tc.Out; !vecNear(tc.Out, tc.In) {
t.Errorf("Fill: Got %#v Want %#v", got, want)
}
}
}
func TestFillAtErrors(t *testing.T) {
unittest.SmallTest(t)
testCases := []struct {
Slice []float32
Idx int
}{
{
Slice: []float32{e, e, 2, 3, e, 5},
Idx: 6,
},
{
Slice: []float32{},
Idx: 0,
},
{
Slice: []float32{4},
Idx: -1,
},
}
for _, tc := range testCases {
_, err := FillAt(tc.Slice, tc.Idx)
if err == nil {
t.Fatalf("Expected \"%v\" to fail FillAt.", tc)
}
}
}
func TestDup(t *testing.T) {
unittest.SmallTest(t)
a := []float32{1, 2, MISSING_DATA_SENTINEL, 0}
b := Dup(a)
assert.Equal(t, a, b)
b[0] = 2
assert.NotEqual(t, a, b)
a = []float32{}
b = Dup(a)
assert.Equal(t, a, b)
}
func TestMean(t *testing.T) {
unittest.SmallTest(t)
testCases := []struct {
Slice []float32
Mean float32
}{
{
Slice: []float32{1, 2, e, 0},
Mean: 1.0,
},
{
Slice: []float32{},
Mean: 0.0,
},
{
Slice: []float32{e},
Mean: 0.0,
},
{
Slice: []float32{e, e},
Mean: 0.0,
},
{
Slice: []float32{1, 5},
Mean: 3.0,
},
}
for _, tc := range testCases {
if got, want := Mean(tc.Slice), tc.Mean; !near(got, want) {
t.Errorf("Mean(%v) Got %v Want %v", tc.Slice, got, want)
}
}
}
func TestSSE(t *testing.T) {
unittest.SmallTest(t)
testCases := []struct {
Slice []float32
Base float32
SSE float32
}{
{
Slice: []float32{1, 1, e, 0},
Base: 0.0,
SSE: 2.0,
},
{
Slice: []float32{1, 1, e, 0},
Base: 1.0,
SSE: 1.0,
},
{
Slice: []float32{},
Base: 1.0,
SSE: 0.0,
},
{
Slice: []float32{e},
Base: 3.0,
SSE: 0.0,
},
}
for _, tc := range testCases {
if got, want := SSE(tc.Slice, tc.Base), tc.SSE; !near(got, want) {
t.Errorf("SSE(%v, %f) Got %v Want %v", tc.Slice, tc.Base, got, want)
}
}
}
func TestFillMeanMissing(t *testing.T) {
unittest.SmallTest(t)
testCases := []struct {
Slice []float32
Mean []float32
}{
{
Slice: []float32{1, 2, e, 0},
Mean: []float32{1.0, 1.0, 1.0, 1.0},
},
{
Slice: []float32{e, e, e, e},
Mean: []float32{e, e, e, e},
},
{
Slice: []float32{e},
Mean: []float32{e},
},
{
Slice: []float32{},
Mean: []float32{},
},
{
Slice: []float32{2.0},
Mean: []float32{2.0},
},
}
for _, tc := range testCases {
v := Dup(tc.Slice)
FillMeanMissing(v)
if got, want := v, tc.Mean; !vecNear(got, want) {
t.Errorf("Mean(%v) Got %v Want %v", tc.Slice, got, want)
}
}
}
func TestFillStdDev(t *testing.T) {
unittest.SmallTest(t)
testCases := []struct {
Slice []float32
Mean []float32
}{
{
Slice: []float32{0, 1, 4, 9},
Mean: []float32{3.5, 3.5, 3.5, 3.5},
},
{
Slice: []float32{e, e, e, e},
Mean: []float32{e, e, e, e},
},
{
Slice: []float32{e},
Mean: []float32{e},
},
{
Slice: []float32{},
Mean: []float32{},
},
{
Slice: []float32{2.0},
Mean: []float32{0.0},
},
}
for _, tc := range testCases {
v := Dup(tc.Slice)
FillStdDev(v)
if got, want := v, tc.Mean; !vecNear(got, want) {
t.Errorf("Mean(%v) Got %v Want %v", tc.Slice, got, want)
}
}
}
func TestFillCov(t *testing.T) {
unittest.SmallTest(t)
testCases := []struct {
Slice []float32
Mean []float32
}{
{
Slice: []float32{0, 1, 4, 9},
Mean: []float32{1, 1, 1, 1},
},
{
Slice: []float32{e, e, e, e},
Mean: []float32{e, e, e, e},
},
{
Slice: []float32{e},
Mean: []float32{e},
},
{
Slice: []float32{},
Mean: []float32{},
},
{
Slice: []float32{2.0},
Mean: []float32{0.0},
},
}
for _, tc := range testCases {
v := Dup(tc.Slice)
FillCov(v)
if got, want := v, tc.Mean; !vecNear(got, want) {
t.Errorf("Mean(%v) Got %v Want %v", tc.Slice, got, want)
}
}
}
func TestScaleBy(t *testing.T) {
unittest.SmallTest(t)
testCases := []struct {
Slice []float32
Scale float32
Expected []float32
}{
{
Slice: []float32{e, 0, 2, 3},
Scale: math.SmallestNonzeroFloat32,
Expected: []float32{e, 0, e, e},
},
{
Slice: []float32{e, 0, -1, 2},
Scale: 0,
Expected: []float32{e, e, e, e},
},
{
Slice: []float32{e, 0, -2, 2},
Scale: 2,
Expected: []float32{e, 0, -1, 1},
},
}
for _, tc := range testCases {
v := Dup(tc.Slice)
ScaleBy(v, tc.Scale)
if got, want := v, tc.Expected; !vecNear(got, want) {
t.Errorf("Mean(%v) Got %v Want %v", tc.Slice, got, want)
}
}
}
func TestFillStep(t *testing.T) {
unittest.SmallTest(t)
testCases := []struct {
Slice []float32
Step []float32
}{
{
Slice: []float32{1, 1, 2, 2, 2},
Step: []float32{0.5, 0.5, 0.5, 0.5, 0.5},
},
{
Slice: []float32{1, 1, 0, 0, 0},
Step: []float32{e, e, e, e, e},
},
{
Slice: []float32{3, 5, 2, 2, 2},
Step: []float32{2, 2, 2, 2, 2},
},
{
Slice: []float32{3, 5, e, 2, 2},
Step: []float32{2, 2, 2, 2, 2},
},
{
Slice: []float32{3, 5, e, e, 2},
Step: []float32{2, 2, 2, 2, 2},
},
{
Slice: []float32{4, e, e, e, 2},
Step: []float32{2, 2, 2, 2, 2},
},
{
Slice: []float32{3, 5, e, e, e},
Step: []float32{e, e, e, e, e},
},
{
Slice: []float32{e, e, e, e},
Step: []float32{e, e, e, e},
},
{
Slice: []float32{e},
Step: []float32{e},
},
{
Slice: []float32{},
Step: []float32{},
},
{
Slice: []float32{1.0},
Step: []float32{e},
},
}
for _, tc := range testCases {
v := Dup(tc.Slice)
FillStep(v)
if got, want := v, tc.Step; !vecNear(got, want) {
t.Errorf("Mean(%v) Got %v Want %v", tc.Slice, got, want)
}
}
}