// Copyright ©2019 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 kdtree import ( "sort" "testing" "golang.org/x/exp/rand" ) type ints []int func (a ints) Len() int { return len(a) } func (a ints) Less(i, j int) bool { return a[i] < a[j] } func (a ints) Slice(s, e int) SortSlicer { return a[s:e] } func (a ints) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func TestPartition(t *testing.T) { rnd := rand.New(rand.NewSource(1)) for p := 0; p < 100; p++ { list := make(ints, 1e5) for i := range list { list[i] = rnd.Int() } pi := Partition(list, rnd.Intn(list.Len())) for i := 0; i < pi; i++ { if list[i] > list[pi] { t.Errorf("unexpected partition sort order p[%d] > p[%d]: %d > %d", i, pi, list[i], list[pi]) } } for i := pi + 1; i < len(list); i++ { if list[i] <= list[pi] { t.Errorf("unexpected partition sort order p[%d] <= p[%d]: %d <= %d", i, pi, list[i], list[pi]) } } } } func TestPartitionCollision(t *testing.T) { rnd := rand.New(rand.NewSource(1)) for p := 0; p < 10; p++ { list := make(ints, 10) for i := range list { list[i] = rnd.Intn(5) } pi := Partition(list, p) for i := 0; i < pi; i++ { if list[i] > list[pi] { t.Errorf("unexpected partition sort order p[%d] > p[%d]: %d > %d", i, pi, list[i], list[pi]) } } for i := pi + 1; i < len(list); i++ { if list[i] <= list[pi] { t.Errorf("unexpected partition sort order p[%d] <= p[%d]: %d <= %d", i, pi, list[i], list[pi]) } } } } func sortSelection(list ints, k int) int { sort.Sort(list) return list[k] } func TestSelect(t *testing.T) { rnd := rand.New(rand.NewSource(1)) for k := 0; k < 2121; k++ { list := make(ints, 2121) for i := range list { list[i] = rnd.Intn(1000) } Select(list, k) sorted := append(ints(nil), list...) want := sortSelection(sorted, k) if list[k] != want { t.Errorf("unexpected result from Select(..., %d): got:%v want:%d", k, list[k], want) } } } func TestMedianOfMedians(t *testing.T) { rnd := rand.New(rand.NewSource(1)) list := make(ints, 1e4) for i := range list { list[i] = rnd.Int() } p := MedianOfMedians(list) med := list[p] sort.Sort(list) var found bool for _, v := range list[len(list)*3/10 : len(list)*7/10+1] { if v == med { found = true break } } if !found { t.Error("failed to find median") } } func TestMedianOfRandoms(t *testing.T) { rnd := rand.New(rand.NewSource(1)) list := make(ints, 1e4) for i := range list { list[i] = rnd.Int() } p := MedianOfRandoms(list, randoms) med := list[p] sort.Sort(list) var found bool for _, v := range list[len(list)*3/10 : len(list)*7/10+1] { if v == med { found = true break } } if !found { t.Error("failed to find median") } } var benchSink int func BenchmarkMedianOfMedians(b *testing.B) { rnd := rand.New(rand.NewSource(1)) for i := 0; i < b.N; i++ { b.StopTimer() list := make(ints, 1e4) for i := range list { list[i] = rnd.Int() } b.StartTimer() benchSink = MedianOfMedians(list) } } func BenchmarkPartitionMedianOfMedians(b *testing.B) { rnd := rand.New(rand.NewSource(1)) for i := 0; i < b.N; i++ { b.StopTimer() list := make(ints, 1e4) for i := range list { list[i] = rnd.Int() } b.StartTimer() benchSink = Partition(list, MedianOfMedians(list)) } } func BenchmarkMedianOfRandoms(b *testing.B) { rnd := rand.New(rand.NewSource(1)) b.StopTimer() list := make(ints, 1e4) for i := range list { list[i] = rnd.Int() } b.StartTimer() for i := 0; i < b.N; i++ { benchSink = MedianOfRandoms(list, list.Len()/1e3) } } func BenchmarkPartitionMedianOfRandoms(b *testing.B) { rnd := rand.New(rand.NewSource(1)) b.StopTimer() list := make(ints, 1e4) for i := range list { list[i] = rnd.Int() } b.StartTimer() for i := 0; i < b.N; i++ { benchSink = Partition(list, MedianOfRandoms(list, list.Len()/1e3)) } }