From 6dca9306eb5de8bbacf46dbd705433eefe42deda Mon Sep 17 00:00:00 2001 From: Minke Zhang Date: Sun, 7 Aug 2022 01:30:42 -0700 Subject: [PATCH 1/9] Update perf test with better configuration option API --- internal/perf/perf_test.go | 24 ++++++++++++------------ internal/perf/util/util.go | 27 +++++++++++++++------------ kd/kd_test.go | 22 +++++++++++----------- 3 files changed, 38 insertions(+), 35 deletions(-) diff --git a/internal/perf/perf_test.go b/internal/perf/perf_test.go index cc88a02..2f52bdb 100644 --- a/internal/perf/perf_test.go +++ b/internal/perf/perf_test.go @@ -33,7 +33,7 @@ var ( ) func TestMain(m *testing.M) { - flag.Var(&SuiteSize, "performance_test_size", "performance test size, one of (small | large)") + flag.Var(&SuiteSize, "performance_test_size", "performance test size, one of (unit | small | large)") flag.Parse() os.Exit(m.Run()) @@ -52,15 +52,15 @@ func BenchmarkNew(b *testing.B) { } var configs []config - for _, k := range util.BenchmarkKRange(SuiteSize) { - for _, n := range util.BenchmarkNRange(SuiteSize) { + for _, k := range SuiteSize.K() { + for _, n := range SuiteSize.N() { configs = append(configs, config{ name: fmt.Sprintf("kyroy/K=%v/N=%v", k, n), k: k, n: n, kyroy: true, }) - for _, size := range util.BenchmarkSizeRange(SuiteSize) { + for _, size := range SuiteSize.LeafSize() { configs = append(configs, config{ name: fmt.Sprintf("Real/K=%v/N=%v/LeafSize=%v", k, n, size), k: k, @@ -103,8 +103,8 @@ func BenchmarkKNN(b *testing.B) { } var configs []config - for _, k := range util.BenchmarkKRange(SuiteSize) { - for _, n := range util.BenchmarkNRange(SuiteSize) { + for _, k := range SuiteSize.K() { + for _, n := range SuiteSize.N() { ps := util.Generate(n, k) // Brute force approach sorts all data, meaning that the @@ -116,7 +116,7 @@ func BenchmarkKNN(b *testing.B) { knn: n, }) - for _, f := range util.BenchmarkFRange(SuiteSize) { + for _, f := range SuiteSize.F() { knn := int(float64(n) * f) // kyroy implementation does not take a @@ -128,7 +128,7 @@ func BenchmarkKNN(b *testing.B) { knn: knn, }) - for _, size := range util.BenchmarkSizeRange(SuiteSize) { + for _, size := range SuiteSize.LeafSize() { configs = append(configs, config{ name: fmt.Sprintf("Real/K=%v/N=%v/LeafSize=%v/KNN=%v", k, n, size, f), t: (*ckd.KD[*mock.P])(unsafe.Pointer( @@ -164,8 +164,8 @@ func BenchmarkRangeSearch(b *testing.B) { } var configs []config - for _, k := range util.BenchmarkKRange(SuiteSize) { - for _, n := range util.BenchmarkNRange(SuiteSize) { + for _, k := range SuiteSize.K() { + for _, n := range SuiteSize.N() { ps := util.Generate(n, k) // Brute force approach sorts all data, meaning that the @@ -176,7 +176,7 @@ func BenchmarkRangeSearch(b *testing.B) { q: util.RH(k, 1), }) - for _, f := range util.BenchmarkFRange(SuiteSize) { + for _, f := range SuiteSize.F() { q := util.RH(k, f) // kyroy implementation does not take a @@ -187,7 +187,7 @@ func BenchmarkRangeSearch(b *testing.B) { q: q, }) - for _, size := range util.BenchmarkSizeRange(SuiteSize) { + for _, size := range SuiteSize.LeafSize() { configs = append(configs, config{ name: fmt.Sprintf("Real/K=%v/N=%v/LeafSize=%v/Coverage=%v", k, n, size, f), t: (*ckd.KD[*mock.P])(unsafe.Pointer( diff --git a/internal/perf/util/util.go b/internal/perf/util/util.go index 170fab5..e957e4a 100644 --- a/internal/perf/util/util.go +++ b/internal/perf/util/util.go @@ -14,23 +14,18 @@ import ( "github.com/google/go-cmp/cmp" ) -var ( - KRange = []vector.D{2} - NRange = []int{1e3} - SizeRange = []int{1, 16} - FRange = []float64{0.05} -) - type PerfTestSize int const ( SizeUnknown PerfTestSize = iota + SizeUnit SizeSmall SizeLarge ) func (s *PerfTestSize) String() string { return map[PerfTestSize]string{ + SizeUnit: "unit", SizeSmall: "small", SizeLarge: "large", }[*s] @@ -38,6 +33,7 @@ func (s *PerfTestSize) String() string { func (s *PerfTestSize) Set(v string) error { size, ok := map[string]PerfTestSize{ + "unit": SizeUnit, "small": SizeSmall, "large": SizeLarge, }[v] @@ -48,26 +44,33 @@ func (s *PerfTestSize) Set(v string) error { return nil } -func BenchmarkFRange(s PerfTestSize) []float64 { +func (s PerfTestSize) F() []float64 { return map[PerfTestSize][]float64{ + SizeUnit: []float64{0.05}, SizeSmall: []float64{0.05}, SizeLarge: []float64{0.05, 0.1, 0.25}, }[s] } -func BenchmarkSizeRange(s PerfTestSize) []int { - return []int{1, 32, 512} +func (s PerfTestSize) LeafSize() []int { + return map[PerfTestSize][]int{ + SizeUnit: []int{1, 16}, + SizeSmall: []int{1, 32, 512}, + SizeLarge: []int{1, 32, 512}, + }[s] } -func BenchmarkNRange(s PerfTestSize) []int { +func (s PerfTestSize) N() []int { return map[PerfTestSize][]int{ + SizeUnit: []int{1e3}, SizeSmall: []int{1e3, 1e4}, SizeLarge: []int{1e3, 1e4, 1e6}, }[s] } -func BenchmarkKRange(s PerfTestSize) []vector.D { +func (s PerfTestSize) K() []vector.D { return map[PerfTestSize][]vector.D{ + SizeUnit: []vector.D{2}, SizeSmall: []vector.D{2, 16}, SizeLarge: []vector.D{2, 16, 128}, }[s] diff --git a/kd/kd_test.go b/kd/kd_test.go index d9a5533..8f364fb 100644 --- a/kd/kd_test.go +++ b/kd/kd_test.go @@ -26,9 +26,9 @@ func TestNew(t *testing.T) { } var configs []config - for _, k := range putil.KRange { - for _, n := range putil.NRange { - for _, size := range putil.SizeRange { + for _, k := range putil.PerfTestSize(putil.SizeUnit).K() { + for _, n := range putil.PerfTestSize(putil.SizeUnit).N() { + for _, size := range putil.PerfTestSize(putil.SizeUnit).LeafSize() { configs = append(configs, config{ name: fmt.Sprintf("K=%v/N=%v/LeafSize=%v", k, n, size), k: k, @@ -123,10 +123,10 @@ func TestKNN(t *testing.T) { } var configs []config - for _, k := range putil.KRange { - for _, n := range putil.NRange { - for _, size := range putil.SizeRange { - for _, f := range putil.FRange { + for _, k := range putil.PerfTestSize(putil.SizeUnit).K() { + for _, n := range putil.PerfTestSize(putil.SizeUnit).N() { + for _, size := range putil.PerfTestSize(putil.SizeUnit).LeafSize() { + for _, f := range putil.PerfTestSize(putil.SizeUnit).F() { configs = append(configs, config{ name: fmt.Sprintf("K=%v/N=%v/LeafSize=%v/KNN=%v", k, n, size, f), k: k, @@ -172,10 +172,10 @@ func TestRangeSearch(t *testing.T) { } var configs []config - for _, k := range putil.KRange { - for _, n := range putil.NRange { - for _, size := range putil.SizeRange { - for _, f := range putil.FRange { + for _, k := range putil.PerfTestSize(putil.SizeUnit).K() { + for _, n := range putil.PerfTestSize(putil.SizeUnit).N() { + for _, size := range putil.PerfTestSize(putil.SizeUnit).LeafSize() { + for _, f := range putil.PerfTestSize(putil.SizeUnit).F() { configs = append(configs, config{ name: fmt.Sprintf("K=%v/N=%v/LeafSize=%v/Coverage=%v", k, n, size, f), k: k, From bb4024a72e1f1ae172338caa1e2adc12ecb7cf28 Mon Sep 17 00:00:00 2001 From: Minke Zhang Date: Sun, 7 Aug 2022 01:32:45 -0700 Subject: [PATCH 2/9] Update perf metrics to be more forgiving for full suite --- internal/perf/util/util.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/internal/perf/util/util.go b/internal/perf/util/util.go index e957e4a..cb9f9af 100644 --- a/internal/perf/util/util.go +++ b/internal/perf/util/util.go @@ -48,7 +48,7 @@ func (s PerfTestSize) F() []float64 { return map[PerfTestSize][]float64{ SizeUnit: []float64{0.05}, SizeSmall: []float64{0.05}, - SizeLarge: []float64{0.05, 0.1, 0.25}, + SizeLarge: []float64{0.05, 0.1}, }[s] } @@ -72,7 +72,10 @@ func (s PerfTestSize) K() []vector.D { return map[PerfTestSize][]vector.D{ SizeUnit: []vector.D{2}, SizeSmall: []vector.D{2, 16}, - SizeLarge: []vector.D{2, 16, 128}, + + // Large tests phyically cannot store enough point data in + // memory with high-dimensional data. + SizeLarge: []vector.D{16}, }[s] } From c2a17956fe02c9d7cf8d522230fd28fcdba5b6d2 Mon Sep 17 00:00:00 2001 From: Minke Zhang Date: Sun, 7 Aug 2022 19:41:56 -0700 Subject: [PATCH 3/9] Update perf flag data and results --- internal/perf/results/v0.5.5.txt | 72 ++++++++++++++++++++++++++++++++ internal/perf/util/util.go | 2 +- 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 internal/perf/results/v0.5.5.txt diff --git a/internal/perf/results/v0.5.5.txt b/internal/perf/results/v0.5.5.txt new file mode 100644 index 0000000..490c723 --- /dev/null +++ b/internal/perf/results/v0.5.5.txt @@ -0,0 +1,72 @@ +goos: linux +goarch: amd64 +pkg: github.com/downflux/go-kd/internal/perf +cpu: Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz +BenchmarkNew/kyroy/K=16/N=1000-8 1528 758980 ns/op 146777 B/op 2524 allocs/op +BenchmarkNew/Real/K=16/N=1000/LeafSize=1-8 3805 276313 ns/op 126098 B/op 2089 allocs/op +BenchmarkNew/Real/K=16/N=1000/LeafSize=16-8 6034 200749 ns/op 32637 B/op 420 allocs/op +BenchmarkNew/Real/K=16/N=1000/LeafSize=256-8 10000 113851 ns/op 12155 B/op 63 allocs/op +BenchmarkNew/kyroy/K=16/N=10000-8 79 15089373 ns/op 1674236 B/op 25924 allocs/op +BenchmarkNew/Real/K=16/N=10000/LeafSize=1-8 514 2201218 ns/op 1263945 B/op 20928 allocs/op +BenchmarkNew/Real/K=16/N=10000/LeafSize=16-8 751 1599132 ns/op 330730 B/op 4264 allocs/op +BenchmarkNew/Real/K=16/N=10000/LeafSize=256-8 886 1273534 ns/op 125601 B/op 692 allocs/op +BenchmarkNew/kyroy/K=16/N=1000000-8 1 7407144200 ns/op 184813784 B/op 2524327 allocs/op +BenchmarkNew/Real/K=16/N=1000000/LeafSize=1-8 2 735249000 ns/op 127022260 B/op 2096135 allocs/op +BenchmarkNew/Real/K=16/N=1000000/LeafSize=16-8 2 559409550 ns/op 33078812 B/op 428590 allocs/op +BenchmarkNew/Real/K=16/N=1000000/LeafSize=256-8 2 588456300 ns/op 12462912 B/op 70330 allocs/op +BenchmarkKNN/BruteForce/K=16/N=1000-8 956 1563019 ns/op 2220712 B/op 17165 allocs/op +BenchmarkKNN/kyroy/K=16/N=1000/KNN=0.05-8 1501 791415 ns/op 21960 B/op 1116 allocs/op +BenchmarkKNN/Real/K=16/N=1000/LeafSize=1/KNN=0.05-8 6880 176106 ns/op 37984 B/op 972 allocs/op +BenchmarkKNN/Real/K=16/N=1000/LeafSize=16/KNN=0.05-8 17564 69537 ns/op 12024 B/op 330 allocs/op +BenchmarkKNN/Real/K=16/N=1000/LeafSize=256/KNN=0.05-8 22638 53922 ns/op 6880 B/op 209 allocs/op +BenchmarkKNN/kyroy/K=16/N=1000/KNN=0.1-8 996 1194847 ns/op 27880 B/op 1242 allocs/op +BenchmarkKNN/Real/K=16/N=1000/LeafSize=1/KNN=0.1-8 6176 196038 ns/op 44184 B/op 1102 allocs/op +BenchmarkKNN/Real/K=16/N=1000/LeafSize=16/KNN=0.1-8 10000 101893 ns/op 17896 B/op 489 allocs/op +BenchmarkKNN/Real/K=16/N=1000/LeafSize=256/KNN=0.1-8 16645 70664 ns/op 10784 B/op 295 allocs/op +BenchmarkKNN/BruteForce/K=16/N=10000-8 74 25007432 ns/op 30633256 B/op 236548 allocs/op +BenchmarkKNN/kyroy/K=16/N=10000/KNN=0.05-8 37 30799189 ns/op 223040 B/op 10906 allocs/op +BenchmarkKNN/Real/K=16/N=10000/LeafSize=1/KNN=0.05-8 654 2057458 ns/op 373568 B/op 9747 allocs/op +BenchmarkKNN/Real/K=16/N=10000/LeafSize=16/KNN=0.05-8 1303 889883 ns/op 118112 B/op 3294 allocs/op +BenchmarkKNN/Real/K=16/N=10000/LeafSize=256/KNN=0.05-8 1663 679360 ns/op 58024 B/op 1741 allocs/op +BenchmarkKNN/kyroy/K=16/N=10000/KNN=0.1-8 13 91103708 ns/op 297008 B/op 12232 allocs/op +BenchmarkKNN/Real/K=16/N=10000/LeafSize=1/KNN=0.1-8 562 2202105 ns/op 413840 B/op 10845 allocs/op +BenchmarkKNN/Real/K=16/N=10000/LeafSize=16/KNN=0.1-8 961 1215787 ns/op 165600 B/op 4681 allocs/op +BenchmarkKNN/Real/K=16/N=10000/LeafSize=256/KNN=0.1-8 1220 984166 ns/op 100272 B/op 2923 allocs/op +BenchmarkKNN/BruteForce/K=16/N=1000000-8 1 5030811400 ns/op 5347687464 B/op 41453237 allocs/op +BenchmarkKNN/kyroy/K=16/N=1000000/KNN=0.05-8 1 529703585200 ns/op 23755688 B/op 1107742 allocs/op +BenchmarkKNN/Real/K=16/N=1000000/LeafSize=1/KNN=0.05-8 3 464044100 ns/op 36143720 B/op 1001542 allocs/op +BenchmarkKNN/Real/K=16/N=1000000/LeafSize=16/KNN=0.05-8 3 347817233 ns/op 11420744 B/op 333388 allocs/op +BenchmarkKNN/Real/K=16/N=1000000/LeafSize=256/KNN=0.05-8 3 335845533 ns/op 6044016 B/op 190971 allocs/op +BenchmarkKNN/kyroy/K=16/N=1000000/KNN=0.1-8 1 1694060569900 ns/op 31972504 B/op 1237806 allocs/op +BenchmarkKNN/Real/K=16/N=1000000/LeafSize=1/KNN=0.1-8 3 501073000 ns/op 40388328 B/op 1130901 allocs/op +BenchmarkKNN/Real/K=16/N=1000000/LeafSize=16/KNN=0.1-8 3 394814333 ns/op 16062312 B/op 473830 allocs/op +BenchmarkKNN/Real/K=16/N=1000000/LeafSize=256/KNN=0.1-8 3 365633867 ns/op 10085976 B/op 304736 allocs/op +BenchmarkRangeSearch/BruteForce/K=16/N=1000-8 7825 154712 ns/op 25208 B/op 12 allocs/op +BenchmarkRangeSearch/kyroy/K=16/N=1000/Coverage=0.05-8 89456 13373 ns/op 496 B/op 5 allocs/op +BenchmarkRangeSearch/Real/K=16/N=1000/LeafSize=1/Coverage=0.05-8 5394 314928 ns/op 207113 B/op 1978 allocs/op +BenchmarkRangeSearch/Real/K=16/N=1000/LeafSize=16/Coverage=0.05-8 7376 193276 ns/op 101603 B/op 970 allocs/op +BenchmarkRangeSearch/Real/K=16/N=1000/LeafSize=256/Coverage=0.05-8 15967 75247 ns/op 21216 B/op 202 allocs/op +BenchmarkRangeSearch/kyroy/K=16/N=1000/Coverage=0.1-8 58239 20985 ns/op 496 B/op 5 allocs/op +BenchmarkRangeSearch/Real/K=16/N=1000/LeafSize=1/Coverage=0.1-8 5154 288420 ns/op 179478 B/op 1714 allocs/op +BenchmarkRangeSearch/Real/K=16/N=1000/LeafSize=16/Coverage=0.1-8 6628 237190 ns/op 121699 B/op 1162 allocs/op +BenchmarkRangeSearch/Real/K=16/N=1000/LeafSize=256/Coverage=0.1-8 16291 69358 ns/op 21216 B/op 202 allocs/op +BenchmarkRangeSearch/BruteForce/K=16/N=10000-8 774 1594897 ns/op 357624 B/op 19 allocs/op +BenchmarkRangeSearch/kyroy/K=16/N=10000/Coverage=0.05-8 5510 205729 ns/op 496 B/op 5 allocs/op +BenchmarkRangeSearch/Real/K=16/N=10000/LeafSize=1/Coverage=0.05-8 4323 332339 ns/op 202086 B/op 1930 allocs/op +BenchmarkRangeSearch/Real/K=16/N=10000/LeafSize=16/Coverage=0.05-8 4491 336055 ns/op 141795 B/op 1354 allocs/op +BenchmarkRangeSearch/Real/K=16/N=10000/LeafSize=256/Coverage=0.05-8 6256 187946 ns/op 46337 B/op 442 allocs/op +BenchmarkRangeSearch/kyroy/K=16/N=10000/Coverage=0.1-8 3904 288862 ns/op 496 B/op 5 allocs/op +BenchmarkRangeSearch/Real/K=16/N=10000/LeafSize=1/Coverage=0.1-8 643 2387566 ns/op 2355150 B/op 22500 allocs/op +BenchmarkRangeSearch/Real/K=16/N=10000/LeafSize=16/Coverage=0.1-8 2816 614839 ns/op 523648 B/op 5002 allocs/op +BenchmarkRangeSearch/Real/K=16/N=10000/LeafSize=256/Coverage=0.1-8 5074 258066 ns/op 101605 B/op 970 allocs/op +BenchmarkRangeSearch/BruteForce/K=16/N=1000000-8 7 173427000 ns/op 41678072 B/op 38 allocs/op +BenchmarkRangeSearch/kyroy/K=16/N=1000000/Coverage=0.05-8 20 56820240 ns/op 496 B/op 5 allocs/op +BenchmarkRangeSearch/Real/K=16/N=1000000/LeafSize=1/Coverage=0.05-8 266 5463061 ns/op 5008653 B/op 47853 allocs/op +BenchmarkRangeSearch/Real/K=16/N=1000000/LeafSize=16/Coverage=0.05-8 698 2587562 ns/op 2242039 B/op 21420 allocs/op +BenchmarkRangeSearch/Real/K=16/N=1000000/LeafSize=256/Coverage=0.05-8 2593 530937 ns/op 212134 B/op 2026 allocs/op +BenchmarkRangeSearch/kyroy/K=16/N=1000000/Coverage=0.1-8 15 76181887 ns/op 496 B/op 5 allocs/op +BenchmarkRangeSearch/Real/K=16/N=1000000/LeafSize=1/Coverage=0.1-8 82 18895179 ns/op 17748509 B/op 169579 allocs/op +BenchmarkRangeSearch/Real/K=16/N=1000000/LeafSize=16/Coverage=0.1-8 150 6825001 ns/op 6734713 B/op 64344 allocs/op +BenchmarkRangeSearch/Real/K=16/N=1000000/LeafSize=256/Coverage=0.1-8 298 4691212 ns/op 2920521 B/op 27902 allocs/op +PASS +ok github.com/downflux/go-kd/internal/perf 2466.847s diff --git a/internal/perf/util/util.go b/internal/perf/util/util.go index cb9f9af..bf6095b 100644 --- a/internal/perf/util/util.go +++ b/internal/perf/util/util.go @@ -56,7 +56,7 @@ func (s PerfTestSize) LeafSize() []int { return map[PerfTestSize][]int{ SizeUnit: []int{1, 16}, SizeSmall: []int{1, 32, 512}, - SizeLarge: []int{1, 32, 512}, + SizeLarge: []int{1, 16, 256}, }[s] } From 05734205f512cce6882dd644154a9b6dcb20a69e Mon Sep 17 00:00:00 2001 From: Minke Zhang Date: Sun, 7 Aug 2022 19:57:05 -0700 Subject: [PATCH 4/9] Update README with perf results --- README.md | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/README.md b/README.md index 8bed8fc..a27aa03 100644 --- a/README.md +++ b/README.md @@ -84,3 +84,51 @@ func main() { } } ``` + +## Performance (@v1.0.0) + +This k-D tree implementation was compared against a brute force method, as well +as with the leading Golang k-D tree implementation +(http://github.com/kyroy/kdtree). Overall, we have found that + +* tree construction is about 10x faster for large N. + +``` +BenchmarkNew/kyroy/K=16/N=1000-8 1528 758980 ns/op 146777 B/op 2524 allocs/op +BenchmarkNew/Real/K=16/N=1000/LeafSize=16-8 6034 200749 ns/op 32637 B/op 420 allocs/op + +BenchmarkNew/kyroy/K=16/N=1000000-8 1 7407144200 ns/op 184813784 B/op 2524327 allocs/op +BenchmarkNew/Real/K=16/N=1000000/LeafSize=256-8 2 588456300 ns/op 12462912 B/op 70330 allocs/op +``` + +* KNN is significantly faster; for small N, we have found our implementation is + ~10x faster than the reference implementation and ~20x faster than brute + force. For large N, we have found up to ~15x faster than brute force, and a + staggering _~1500x_ speedup when compared to the reference implementation. + +``` +BenchmarkKNN/BruteForce/K=16/N=1000-8 956 1563019 ns/op 2220712 B/op 17165 allocs/op +BenchmarkKNN/kyroy/K=16/N=1000/KNN=0.05-8 1501 791415 ns/op 21960 B/op 1116 allocs/op +BenchmarkKNN/Real/K=16/N=1000/LeafSize=16/KNN=0.05-8 17564 69537 ns/op 12024 B/op 330 allocs/op + +BenchmarkKNN/BruteForce/K=16/N=1000000-8 1 5030811400 ns/op 5347687464 B/op 41453237 allocs/op +BenchmarkKNN/kyroy/K=16/N=1000000/KNN=0.05-8 1 529703585200 ns/op 23755688 B/op 1107742 allocs/op +BenchmarkKNN/Real/K=16/N=1000000/LeafSize=256/KNN=0.05-8 3 335845533 ns/op 6044016 B/op 190971 allocs/op +``` + +* RangeSearch is slower for small N -- we are approximately at parity for brute + force, and ~10x slower than the reference implementation. However, at large N, + we are ~300x faster than brute force, and ~100x faster than the reference + implementation. + +``` +BenchmarkRangeSearch/BruteForce/K=16/N=1000-8 7825 154712 ns/op 25208 B/op 12 allocs/op +BenchmarkRangeSearch/kyroy/K=16/N=1000/Coverage=0.05-8 89456 13373 ns/op 496 B/op 5 allocs/op +BenchmarkRangeSearch/Real/K=16/N=1000/LeafSize=16/Coverage=0.05-8 7376 193276 ns/op 101603 B/op 970 allocs/op + +BenchmarkRangeSearch/BruteForce/K=16/N=1000000-8 7 173427000 ns/op 41678072 B/op 38 allocs/op +BenchmarkRangeSearch/kyroy/K=16/N=1000000/Coverage=0.05-8 20 56820240 ns/op 496 B/op 5 allocs/op +BenchmarkRangeSearch/Real/K=16/N=1000000/LeafSize=256/Coverage=0.05-8 2593 530937 ns/op 212134 B/op 2026 allocs/op +``` + +Raw data on these results may be found [here](/internal/perf/results/v0.5.5.txt). From c560dd61570fac4dd6929cbbc29a97a7cdfb8670 Mon Sep 17 00:00:00 2001 From: Minke Zhang Date: Sun, 7 Aug 2022 20:00:22 -0700 Subject: [PATCH 5/9] Reformat README --- README.md | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index a27aa03..cd4d9c9 100644 --- a/README.md +++ b/README.md @@ -93,42 +93,42 @@ as with the leading Golang k-D tree implementation * tree construction is about 10x faster for large N. -``` -BenchmarkNew/kyroy/K=16/N=1000-8 1528 758980 ns/op 146777 B/op 2524 allocs/op -BenchmarkNew/Real/K=16/N=1000/LeafSize=16-8 6034 200749 ns/op 32637 B/op 420 allocs/op + ``` + BenchmarkNew/kyroy/K=16/N=1000-8 1528 758980 ns/op 146777 B/op 2524 allocs/op + BenchmarkNew/Real/K=16/N=1000/LeafSize=16-8 6034 200749 ns/op 32637 B/op 420 allocs/op -BenchmarkNew/kyroy/K=16/N=1000000-8 1 7407144200 ns/op 184813784 B/op 2524327 allocs/op -BenchmarkNew/Real/K=16/N=1000000/LeafSize=256-8 2 588456300 ns/op 12462912 B/op 70330 allocs/op -``` + BenchmarkNew/kyroy/K=16/N=1000000-8 1 7407144200 ns/op 184813784 B/op 2524327 allocs/op + BenchmarkNew/Real/K=16/N=1000000/LeafSize=256-8 2 588456300 ns/op 12462912 B/op 70330 allocs/op + ``` * KNN is significantly faster; for small N, we have found our implementation is ~10x faster than the reference implementation and ~20x faster than brute force. For large N, we have found up to ~15x faster than brute force, and a staggering _~1500x_ speedup when compared to the reference implementation. -``` -BenchmarkKNN/BruteForce/K=16/N=1000-8 956 1563019 ns/op 2220712 B/op 17165 allocs/op -BenchmarkKNN/kyroy/K=16/N=1000/KNN=0.05-8 1501 791415 ns/op 21960 B/op 1116 allocs/op -BenchmarkKNN/Real/K=16/N=1000/LeafSize=16/KNN=0.05-8 17564 69537 ns/op 12024 B/op 330 allocs/op + ``` + BenchmarkKNN/BruteForce/K=16/N=1000-8 956 1563019 ns/op 2220712 B/op 17165 allocs/op + BenchmarkKNN/kyroy/K=16/N=1000/KNN=0.05-8 1501 791415 ns/op 21960 B/op 1116 allocs/op + BenchmarkKNN/Real/K=16/N=1000/LeafSize=16/KNN=0.05-8 17564 69537 ns/op 12024 B/op 330 allocs/op -BenchmarkKNN/BruteForce/K=16/N=1000000-8 1 5030811400 ns/op 5347687464 B/op 41453237 allocs/op -BenchmarkKNN/kyroy/K=16/N=1000000/KNN=0.05-8 1 529703585200 ns/op 23755688 B/op 1107742 allocs/op -BenchmarkKNN/Real/K=16/N=1000000/LeafSize=256/KNN=0.05-8 3 335845533 ns/op 6044016 B/op 190971 allocs/op -``` + BenchmarkKNN/BruteForce/K=16/N=1000000-8 1 5030811400 ns/op 5347687464 B/op 41453237 allocs/op + BenchmarkKNN/kyroy/K=16/N=1000000/KNN=0.05-8 1 529703585200 ns/op 23755688 B/op 1107742 allocs/op + BenchmarkKNN/Real/K=16/N=1000000/LeafSize=256/KNN=0.05-8 3 335845533 ns/op 6044016 B/op 190971 allocs/op + ``` * RangeSearch is slower for small N -- we are approximately at parity for brute force, and ~10x slower than the reference implementation. However, at large N, we are ~300x faster than brute force, and ~100x faster than the reference implementation. -``` -BenchmarkRangeSearch/BruteForce/K=16/N=1000-8 7825 154712 ns/op 25208 B/op 12 allocs/op -BenchmarkRangeSearch/kyroy/K=16/N=1000/Coverage=0.05-8 89456 13373 ns/op 496 B/op 5 allocs/op -BenchmarkRangeSearch/Real/K=16/N=1000/LeafSize=16/Coverage=0.05-8 7376 193276 ns/op 101603 B/op 970 allocs/op + ``` + BenchmarkRangeSearch/BruteForce/K=16/N=1000-8 7825 154712 ns/op 25208 B/op 12 allocs/op + BenchmarkRangeSearch/kyroy/K=16/N=1000/Coverage=0.05-8 89456 13373 ns/op 496 B/op 5 allocs/op + BenchmarkRangeSearch/Real/K=16/N=1000/LeafSize=16/Coverage=0.05-8 7376 193276 ns/op 101603 B/op 970 allocs/op -BenchmarkRangeSearch/BruteForce/K=16/N=1000000-8 7 173427000 ns/op 41678072 B/op 38 allocs/op -BenchmarkRangeSearch/kyroy/K=16/N=1000000/Coverage=0.05-8 20 56820240 ns/op 496 B/op 5 allocs/op -BenchmarkRangeSearch/Real/K=16/N=1000000/LeafSize=256/Coverage=0.05-8 2593 530937 ns/op 212134 B/op 2026 allocs/op -``` + BenchmarkRangeSearch/BruteForce/K=16/N=1000000-8 7 173427000 ns/op 41678072 B/op 38 allocs/op + BenchmarkRangeSearch/kyroy/K=16/N=1000000/Coverage=0.05-8 20 56820240 ns/op 496 B/op 5 allocs/op + BenchmarkRangeSearch/Real/K=16/N=1000000/LeafSize=256/Coverage=0.05-8 2593 530937 ns/op 212134 B/op 2026 allocs/op + ``` Raw data on these results may be found [here](/internal/perf/results/v0.5.5.txt). From 0ed5c34d09ab9ac1855427d9d1767894976cedb4 Mon Sep 17 00:00:00 2001 From: Minke Zhang Date: Sun, 7 Aug 2022 20:08:21 -0700 Subject: [PATCH 6/9] Reformat perf data to be more readable in README --- README.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index cd4d9c9..10da5d4 100644 --- a/README.md +++ b/README.md @@ -94,11 +94,11 @@ as with the leading Golang k-D tree implementation * tree construction is about 10x faster for large N. ``` - BenchmarkNew/kyroy/K=16/N=1000-8 1528 758980 ns/op 146777 B/op 2524 allocs/op - BenchmarkNew/Real/K=16/N=1000/LeafSize=16-8 6034 200749 ns/op 32637 B/op 420 allocs/op + BenchmarkNew/kyroy/K=16/N=1000-8 758980 ns/op 146777 B/op + BenchmarkNew/Real/K=16/N=1000/LeafSize=16-8d 200749 ns/op 32637 B/op - BenchmarkNew/kyroy/K=16/N=1000000-8 1 7407144200 ns/op 184813784 B/op 2524327 allocs/op - BenchmarkNew/Real/K=16/N=1000000/LeafSize=256-8 2 588456300 ns/op 12462912 B/op 70330 allocs/op + BenchmarkNew/kyroy/K=16/N=1000000-8 7407144200 ns/op 184813784 B/op + BenchmarkNew/Real/K=16/N=1000000/LeafSize=256-8 588456300 ns/op 12462912 B/op ``` * KNN is significantly faster; for small N, we have found our implementation is @@ -107,13 +107,13 @@ as with the leading Golang k-D tree implementation staggering _~1500x_ speedup when compared to the reference implementation. ``` - BenchmarkKNN/BruteForce/K=16/N=1000-8 956 1563019 ns/op 2220712 B/op 17165 allocs/op - BenchmarkKNN/kyroy/K=16/N=1000/KNN=0.05-8 1501 791415 ns/op 21960 B/op 1116 allocs/op - BenchmarkKNN/Real/K=16/N=1000/LeafSize=16/KNN=0.05-8 17564 69537 ns/op 12024 B/op 330 allocs/op + BenchmarkKNN/BruteForce/K=16/N=1000-8 1563019 ns/op 2220712 B/op + BenchmarkKNN/kyroy/K=16/N=1000/KNN=0.05-8 791415 ns/op 21960 B/op + BenchmarkKNN/Real/K=16/N=1000/LeafSize=16/KNN=0.05-8 69537 ns/op 12024 B/op - BenchmarkKNN/BruteForce/K=16/N=1000000-8 1 5030811400 ns/op 5347687464 B/op 41453237 allocs/op - BenchmarkKNN/kyroy/K=16/N=1000000/KNN=0.05-8 1 529703585200 ns/op 23755688 B/op 1107742 allocs/op - BenchmarkKNN/Real/K=16/N=1000000/LeafSize=256/KNN=0.05-8 3 335845533 ns/op 6044016 B/op 190971 allocs/op + BenchmarkKNN/BruteForce/K=16/N=1000000-8 5030811400 ns/op 5347687464 B/op + BenchmarkKNN/kyroy/K=16/N=1000000/KNN=0.05-8 529703585200 ns/op 23755688 B/op + BenchmarkKNN/Real/K=16/N=1000000/LeafSize=256/KNN=0.05-8 335845533 ns/op 6044016 B/op ``` * RangeSearch is slower for small N -- we are approximately at parity for brute @@ -122,13 +122,13 @@ as with the leading Golang k-D tree implementation implementation. ``` - BenchmarkRangeSearch/BruteForce/K=16/N=1000-8 7825 154712 ns/op 25208 B/op 12 allocs/op - BenchmarkRangeSearch/kyroy/K=16/N=1000/Coverage=0.05-8 89456 13373 ns/op 496 B/op 5 allocs/op - BenchmarkRangeSearch/Real/K=16/N=1000/LeafSize=16/Coverage=0.05-8 7376 193276 ns/op 101603 B/op 970 allocs/op + BenchmarkRangeSearch/BruteForce/K=16/N=1000-8 154712 ns/op 25208 B/op + BenchmarkRangeSearch/kyroy/K=16/N=1000/Coverage=0.05-8 13373 ns/op 496 B/op + BenchmarkRangeSearch/Real/K=16/N=1000/LeafSize=16/Coverage=0.05-8 193276 ns/op 101603 B/op - BenchmarkRangeSearch/BruteForce/K=16/N=1000000-8 7 173427000 ns/op 41678072 B/op 38 allocs/op - BenchmarkRangeSearch/kyroy/K=16/N=1000000/Coverage=0.05-8 20 56820240 ns/op 496 B/op 5 allocs/op - BenchmarkRangeSearch/Real/K=16/N=1000000/LeafSize=256/Coverage=0.05-8 2593 530937 ns/op 212134 B/op 2026 allocs/op + BenchmarkRangeSearch/BruteForce/K=16/N=1000000-8 173427000 ns/op 41678072 B/op + BenchmarkRangeSearch/kyroy/K=16/N=1000000/Coverage=0.05-8 56820240 ns/op 496 B/op + BenchmarkRangeSearch/Real/K=16/N=1000000/LeafSize=256/Coverage=0.05-8 530937 ns/op 212134 B/op ``` Raw data on these results may be found [here](/internal/perf/results/v0.5.5.txt). From a049a05170b917a98f6ea74f4c6881e2941c5c55 Mon Sep 17 00:00:00 2001 From: Minke Zhang Date: Sun, 7 Aug 2022 20:13:19 -0700 Subject: [PATCH 7/9] Reformat perf data to be more readable in README --- README.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 10da5d4..ed0244e 100644 --- a/README.md +++ b/README.md @@ -94,11 +94,11 @@ as with the leading Golang k-D tree implementation * tree construction is about 10x faster for large N. ``` - BenchmarkNew/kyroy/K=16/N=1000-8 758980 ns/op 146777 B/op - BenchmarkNew/Real/K=16/N=1000/LeafSize=16-8d 200749 ns/op 32637 B/op + BenchmarkNew/kyroy/K=16/N=1000-8 758980 ns/op 146777 B/op + BenchmarkNew/Real/K=16/N=1000/LeafSize=16-8 200749 ns/op 32637 B/op - BenchmarkNew/kyroy/K=16/N=1000000-8 7407144200 ns/op 184813784 B/op - BenchmarkNew/Real/K=16/N=1000000/LeafSize=256-8 588456300 ns/op 12462912 B/op + BenchmarkNew/kyroy/K=16/N=1000000-8 7407144200 ns/op 184813784 B/op + BenchmarkNew/Real/K=16/N=1000000/LeafSize=256-8 588456300 ns/op 12462912 B/op ``` * KNN is significantly faster; for small N, we have found our implementation is @@ -107,13 +107,13 @@ as with the leading Golang k-D tree implementation staggering _~1500x_ speedup when compared to the reference implementation. ``` - BenchmarkKNN/BruteForce/K=16/N=1000-8 1563019 ns/op 2220712 B/op - BenchmarkKNN/kyroy/K=16/N=1000/KNN=0.05-8 791415 ns/op 21960 B/op - BenchmarkKNN/Real/K=16/N=1000/LeafSize=16/KNN=0.05-8 69537 ns/op 12024 B/op + BenchmarkKNN/BruteForce/K=16/N=1000-8 1563019 ns/op 2220712 B/op + BenchmarkKNN/kyroy/K=16/N=1000/KNN=0.05-8 791415 ns/op 21960 B/op + BenchmarkKNN/Real/K=16/N=1000/LeafSize=16/KNN=0.05-8 69537 ns/op 12024 B/op - BenchmarkKNN/BruteForce/K=16/N=1000000-8 5030811400 ns/op 5347687464 B/op - BenchmarkKNN/kyroy/K=16/N=1000000/KNN=0.05-8 529703585200 ns/op 23755688 B/op - BenchmarkKNN/Real/K=16/N=1000000/LeafSize=256/KNN=0.05-8 335845533 ns/op 6044016 B/op + BenchmarkKNN/BruteForce/K=16/N=1000000-8 5030811400 ns/op 5347687464 B/op + BenchmarkKNN/kyroy/K=16/N=1000000/KNN=0.05-8 529703585200 ns/op 23755688 B/op + BenchmarkKNN/Real/K=16/N=1000000/LeafSize=256/KNN=0.05-8 335845533 ns/op 6044016 B/op ``` * RangeSearch is slower for small N -- we are approximately at parity for brute @@ -122,13 +122,13 @@ as with the leading Golang k-D tree implementation implementation. ``` - BenchmarkRangeSearch/BruteForce/K=16/N=1000-8 154712 ns/op 25208 B/op - BenchmarkRangeSearch/kyroy/K=16/N=1000/Coverage=0.05-8 13373 ns/op 496 B/op - BenchmarkRangeSearch/Real/K=16/N=1000/LeafSize=16/Coverage=0.05-8 193276 ns/op 101603 B/op + BenchmarkRangeSearch/BruteForce/K=16/N=1000-8 154712 ns/op 25208 B/op + BenchmarkRangeSearch/kyroy/K=16/N=1000/Coverage=0.05-8 13373 ns/op 496 B/op + BenchmarkRangeSearch/Real/K=16/N=1000/LeafSize=16/Coverage=0.05-8 193276 ns/op 101603 B/op - BenchmarkRangeSearch/BruteForce/K=16/N=1000000-8 173427000 ns/op 41678072 B/op - BenchmarkRangeSearch/kyroy/K=16/N=1000000/Coverage=0.05-8 56820240 ns/op 496 B/op - BenchmarkRangeSearch/Real/K=16/N=1000000/LeafSize=256/Coverage=0.05-8 530937 ns/op 212134 B/op + BenchmarkRangeSearch/BruteForce/K=16/N=1000000-8 173427000 ns/op 41678072 B/op + BenchmarkRangeSearch/kyroy/K=16/N=1000000/Coverage=0.05-8 56820240 ns/op 496 B/op + BenchmarkRangeSearch/Real/K=16/N=1000000/LeafSize=256/Coverage=0.05-8 530937 ns/op 212134 B/op ``` Raw data on these results may be found [here](/internal/perf/results/v0.5.5.txt). From 2e99e041fa5d9990612400c4da3bafd410a5c49b Mon Sep 17 00:00:00 2001 From: Minke Zhang Date: Tue, 16 Aug 2022 01:33:18 -0700 Subject: [PATCH 8/9] Migrate to downflux/go-pq --- go.mod | 1 + go.sum | 9 +++ internal/knn/knn.go | 2 +- point/pq/pq.go | 94 ---------------------- point/pq/pq_test.go | 184 -------------------------------------------- 5 files changed, 11 insertions(+), 279 deletions(-) delete mode 100644 point/pq/pq.go delete mode 100644 point/pq/pq_test.go diff --git a/go.mod b/go.mod index 4840da8..aadc176 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.18 require ( github.com/downflux/go-geometry v0.10.2 + github.com/downflux/go-pq v0.1.0 github.com/google/go-cmp v0.5.8 github.com/kyroy/kdtree v0.0.0-20200419114247-70830f883f1d ) diff --git a/go.sum b/go.sum index 912433d..ffc7196 100644 --- a/go.sum +++ b/go.sum @@ -1,15 +1,24 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/downflux/go-geometry v0.10.2 h1:Z79Khzl6AKMSMLnM5xG75fEOL1fmIWlF14+8j+r01D0= github.com/downflux/go-geometry v0.10.2/go.mod h1:XWTzSaMiRMAxupAR+cXAsa1Q75TCSp1Shc/ydsJ0xVE= +github.com/downflux/go-pq v0.0.0-20220816082715-9b33bb1312b1 h1:RxUP6c/xaOXsbYutiupvFqTO3V6HhbUgHxqBr9aF9kY= +github.com/downflux/go-pq v0.0.0-20220816082715-9b33bb1312b1/go.mod h1:6amZrMlYUeY1Ba9T+0A11y2BBENzsUqMmu4o5CMndMk= +github.com/downflux/go-pq v0.1.0 h1:+W2Vp9w2W9fbYruQFyPEIkHwlULzS0OJ11q+JXAeOJ0= +github.com/downflux/go-pq v0.1.0/go.mod h1:6amZrMlYUeY1Ba9T+0A11y2BBENzsUqMmu4o5CMndMk= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/jupp0r/go-priority-queue v0.0.0-20160601094913-ab1073853bde h1:+5PMaaQtDUwOcJIUlmX89P0J3iwTvErTmyn5WghzXAQ= github.com/jupp0r/go-priority-queue v0.0.0-20160601094913-ab1073853bde/go.mod h1:RDgD/dfPmIwFH0qdUOjw71HjtWg56CtyLIoHL+R1wJw= github.com/kyroy/kdtree v0.0.0-20200419114247-70830f883f1d h1:1n5M/49q9H6QtNJiiVL/W5mqgT1UdlGQ7oLP+DkJ1vs= github.com/kyroy/kdtree v0.0.0-20200419114247-70830f883f1d/go.mod h1:6oJGQK7VSg3RxSQ7QspgqpCmKjIbAslgT2wBXbFJUZw= github.com/kyroy/priority-queue v0.0.0-20180327160706-6e21825e7e0c h1:1c7+XOOGQ19cXjZ1Ss/irljQxgPvb+8z+jNEprCXl20= github.com/kyroy/priority-queue v0.0.0-20180327160706-6e21825e7e0c/go.mod h1:R477L6j2/dUcE0q0aftk0kR5Xt93W7g1066AodcJhEo= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/internal/knn/knn.go b/internal/knn/knn.go index bef6811..7cb8f11 100644 --- a/internal/knn/knn.go +++ b/internal/knn/knn.go @@ -5,7 +5,7 @@ import ( "github.com/downflux/go-kd/internal/node" "github.com/downflux/go-kd/point" - "github.com/downflux/go-kd/point/pq" + "github.com/downflux/go-pq/pq" "github.com/downflux/go-kd/vector" vnd "github.com/downflux/go-geometry/nd/vector" diff --git a/point/pq/pq.go b/point/pq/pq.go deleted file mode 100644 index 7dff0af..0000000 --- a/point/pq/pq.go +++ /dev/null @@ -1,94 +0,0 @@ -package pq - -import ( - "container/heap" - "math" - - "github.com/downflux/go-kd/point" -) - -type node[T point.P] struct { - p T - index int - weight float64 -} - -// max implements the heap.Interface. -// -// See https://pkg.go.dev/container/heap for the heap implementation from which -// this was shamelessly stolen. -type max[T point.P] []*node[T] - -func (heap *max[T]) Len() int { return len(*heap) } -func (heap *max[T]) Less(i, j int) bool { return (*heap)[i].weight > (*heap)[j].weight } -func (heap *max[T]) Swap(i, j int) { - (*heap)[i], (*heap)[j] = (*heap)[j], (*heap)[i] - (*heap)[i].index = i - (*heap)[j].index = j -} -func (heap *max[T]) Push(x any) { - m := x.(*node[T]) - m.index = heap.Len() - *heap = append(*heap, m) -} -func (heap *max[T]) Pop() any { - h := *heap - n := len(h) - m := h[n-1] - - h[n-1] = nil - m.index = -1 - - *heap = h[0 : n-1] - return m -} - -// PQ is an exported priority queue of k-D tree nodes with a maximum queue size. -// PQ tracks a specified number points with the smallest given priorities -- -// attempting to add a point with a larger priority will result in an effective -// no-op. -type PQ[T point.P] struct { - heap *max[T] - n int -} - -func New[T point.P](size int) *PQ[T] { - h := max[T](make([]*node[T], 0, size)) - pq := &PQ[T]{ - heap: &h, - n: size, - } - heap.Init(pq.heap) - return pq -} - -func (pq *PQ[T]) Len() int { return pq.heap.Len() } -func (pq *PQ[T]) Empty() bool { return pq.Len() == 0 } -func (pq *PQ[T]) Full() bool { return pq.Len() >= pq.n } - -// Priority calculates the current highest priority of the queue. -func (pq *PQ[T]) Priority() float64 { - if pq.Empty() { - return math.Inf(0) - } - - // See https://groups.google.com/g/golang-nuts/c/sy1p8SfyPoY. - return (*pq.heap)[0].weight -} - -// Push adds a new point into the queue. -// -// The queue will enforce the struct size constraint by removing elements frmo -// itself until the constraint is satisfied. -func (pq *PQ[T]) Push(p T, priority float64) { - heap.Push(pq.heap, &node[T]{ - p: p, - weight: priority, - }) - for !pq.Empty() && pq.Len() > pq.n { - pq.Pop() - } -} - -// Pop removes the node with the highest priority from the queue. -func (pq *PQ[T]) Pop() T { return heap.Pop(pq.heap).(*node[T]).p } diff --git a/point/pq/pq_test.go b/point/pq/pq_test.go deleted file mode 100644 index 85e047a..0000000 --- a/point/pq/pq_test.go +++ /dev/null @@ -1,184 +0,0 @@ -package pq - -import ( - "container/heap" - "testing" - - "github.com/downflux/go-kd/point/mock" - "github.com/google/go-cmp/cmp" -) - -var _ heap.Interface = &max[mock.P]{} - -func TestPQ(t *testing.T) { - type item struct { - p mock.P - priority float64 - } - - type config struct { - name string - data []item - size int - want []mock.P - } - - configs := []config{ - { - name: "Null", - data: nil, - want: nil, - }, - - { - name: "Trivial", - data: []item{ - { - p: mock.P{ - X: mock.U(1), - }, - priority: 0, - }, - }, - size: 1, - want: []mock.P{ - mock.P{ - X: mock.U(1), - }, - }, - }, - { - name: "Trivial/NoSize", - data: []item{ - { - p: mock.P{ - X: mock.U(1), - }, - priority: 0, - }, - }, - size: 0, - want: nil, - }, - - { - name: "Sorted", - data: []item{ - { - p: mock.P{X: mock.U(0)}, - priority: 5, - }, - { - p: mock.P{X: mock.U(-1)}, - priority: 4, - }, - { - p: mock.P{X: mock.U(-2)}, - priority: 3, - }, - { - p: mock.P{X: mock.U(-3)}, - priority: 2, - }, - { - p: mock.P{X: mock.U(-4)}, - priority: 1, - }, - }, - size: 5, - want: []mock.P{ - mock.P{X: mock.U(0)}, - mock.P{X: mock.U(-1)}, - mock.P{X: mock.U(-2)}, - mock.P{X: mock.U(-3)}, - mock.P{X: mock.U(-4)}, - }, - }, - { - name: "Sorted/Reverse", - data: []item{ - { - p: mock.P{X: mock.U(0)}, - priority: 1, - }, - { - p: mock.P{X: mock.U(-1)}, - priority: 2, - }, - { - p: mock.P{X: mock.U(-2)}, - priority: 3, - }, - { - p: mock.P{X: mock.U(-3)}, - priority: 4, - }, - { - p: mock.P{X: mock.U(-4)}, - priority: 5, - }, - }, - size: 5, - want: []mock.P{ - mock.P{X: mock.U(-4)}, - mock.P{X: mock.U(-3)}, - mock.P{X: mock.U(-2)}, - mock.P{X: mock.U(-1)}, - mock.P{X: mock.U(0)}, - }, - }, - { - name: "Sorted/Shuffled", - data: []item{ - { - p: mock.P{X: mock.U(0)}, - priority: 4, - }, - { - p: mock.P{X: mock.U(-1)}, - priority: 2, - }, - { - p: mock.P{X: mock.U(-2)}, - priority: 5, - }, - { - p: mock.P{X: mock.U(-3)}, - priority: 1, - }, - { - p: mock.P{X: mock.U(-4)}, - priority: 3, - }, - }, - size: 5, - want: []mock.P{ - mock.P{X: mock.U(-2)}, - mock.P{X: mock.U(0)}, - mock.P{X: mock.U(-4)}, - mock.P{X: mock.U(-1)}, - mock.P{X: mock.U(-3)}, - }, - }, - } - - for _, c := range configs { - t.Run(c.name, func(t *testing.T) { - pq := New[mock.P](c.size) - for _, d := range c.data { - pq.Push(d.p, d.priority) - } - - var got []mock.P - for !pq.Empty() { - got = append(got, pq.Pop()) - } - - if diff := cmp.Diff( - c.want, got, - ); diff != "" { - t.Errorf("Pop() mismatch (-want +got):\n%v", diff) - } - }) - } -} From d073e09e701678168157c3d8f38a814b065b01cd Mon Sep 17 00:00:00 2001 From: Minke Zhang Date: Tue, 16 Aug 2022 01:45:54 -0700 Subject: [PATCH 9/9] Bump PQ version --- go.mod | 2 +- go.sum | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index aadc176..d6dd020 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.18 require ( github.com/downflux/go-geometry v0.10.2 - github.com/downflux/go-pq v0.1.0 + github.com/downflux/go-pq v0.1.1 github.com/google/go-cmp v0.5.8 github.com/kyroy/kdtree v0.0.0-20200419114247-70830f883f1d ) diff --git a/go.sum b/go.sum index ffc7196..96a1da9 100644 --- a/go.sum +++ b/go.sum @@ -2,10 +2,8 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/downflux/go-geometry v0.10.2 h1:Z79Khzl6AKMSMLnM5xG75fEOL1fmIWlF14+8j+r01D0= github.com/downflux/go-geometry v0.10.2/go.mod h1:XWTzSaMiRMAxupAR+cXAsa1Q75TCSp1Shc/ydsJ0xVE= -github.com/downflux/go-pq v0.0.0-20220816082715-9b33bb1312b1 h1:RxUP6c/xaOXsbYutiupvFqTO3V6HhbUgHxqBr9aF9kY= -github.com/downflux/go-pq v0.0.0-20220816082715-9b33bb1312b1/go.mod h1:6amZrMlYUeY1Ba9T+0A11y2BBENzsUqMmu4o5CMndMk= -github.com/downflux/go-pq v0.1.0 h1:+W2Vp9w2W9fbYruQFyPEIkHwlULzS0OJ11q+JXAeOJ0= -github.com/downflux/go-pq v0.1.0/go.mod h1:6amZrMlYUeY1Ba9T+0A11y2BBENzsUqMmu4o5CMndMk= +github.com/downflux/go-pq v0.1.1 h1:dwWLUMBiUTrZO+TlD+oHPQqsqQDo3f7Yyo8nvO1CV7Y= +github.com/downflux/go-pq v0.1.1/go.mod h1:6amZrMlYUeY1Ba9T+0A11y2BBENzsUqMmu4o5CMndMk= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/jupp0r/go-priority-queue v0.0.0-20160601094913-ab1073853bde h1:+5PMaaQtDUwOcJIUlmX89P0J3iwTvErTmyn5WghzXAQ=