Skip to content

Commit

Permalink
more splits before search
Browse files Browse the repository at this point in the history
  • Loading branch information
gaissmai committed Jan 28, 2023
1 parent b2ea9cb commit 2fd601d
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 24 deletions.
22 changes: 5 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,24 +192,9 @@ BenchmarkCoverLCP/In100_000-8 1533745 782 ns/op 0 B/op 0
BenchmarkCoverLCP/In1_000_000-8 1732171 693 ns/op 0 B/op 0 allocs/op
```

... also for `CoverSCP()`:


```
$ go test -benchmem -bench='CoverSCP'
goos: linux
goarch: amd64
pkg: github.com/gaissmai/interval
cpu: Intel(R) Core(TM) i5-8250U CPU @ 1.60GHz
BenchmarkCoverSCP/In100-8 11576743 95 ns/op 0 B/op 0 allocs/op
BenchmarkCoverSCP/In1_000-8 10032699 114 ns/op 0 B/op 0 allocs/op
BenchmarkCoverSCP/In10_000-8 6087580 196 ns/op 0 B/op 0 allocs/op
BenchmarkCoverSCP/In100_000-8 5949422 202 ns/op 0 B/op 0 allocs/op
BenchmarkCoverSCP/In1_000_000-8 4775067 250 ns/op 0 B/op 0 allocs/op
```

... and for `Intersects()`:


```
$ go test -benchmem -bench='Intersects'
goos: linux
Expand All @@ -225,7 +210,7 @@ BenchmarkIntersects/In100_000-4 7483621 191 ns/op 0 B/op 0
BenchmarkIntersects/In1_000_000-4 8134428 149 ns/op 0 B/op 0 allocs/op
```

... and for Find(), the exact match:
... or Find(), the exact match:

```
$ go test -benchmem -bench='Find'
Expand All @@ -239,3 +224,6 @@ BenchmarkFind/In10_000-8 12858908 90 ns/op 0 B/op 0 al
BenchmarkFind/In100_000-8 4696676 256 ns/op 0 B/op 0 allocs/op
BenchmarkFind/In1_000_000-8 7131028 163 ns/op 0 B/op 0 allocs/op
```

With all other methods, the treap is split before the search, which allocates memory
but minimises the search space.
80 changes: 78 additions & 2 deletions bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,22 @@ func BenchmarkIntersects(b *testing.B) {
}
}

func BenchmarkIntersects2(b *testing.B) {
for n := 1; n <= 1_000_000; n *= 10 {
ivals := genUintIvals(n)
tree := interval.NewTree(cmpUintInterval, ivals...)
probe := gen2UintIvals(1)[0]
name := "In" + intMap[n]

b.Run(name, func(b *testing.B) {
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = tree.Intersects(probe)
}
})
}
}

func BenchmarkFind(b *testing.B) {
for n := 1; n <= 1_000_000; n *= 10 {
ivals := genUintIvals(n)
Expand Down Expand Up @@ -173,6 +189,21 @@ func BenchmarkCoverLCP(b *testing.B) {
}
}

func BenchmarkCoverLCP2(b *testing.B) {
for n := 100; n <= 1_000_000; n *= 10 {
tree := interval.NewTree(cmpUintInterval, gen2UintIvals(n)...)
probe := genUintIvals(1)[0]
name := "In" + intMap[n]

b.Run(name, func(b *testing.B) {
b.ResetTimer()
for n := 0; n < b.N; n++ {
_, _ = tree.CoverLCP(probe)
}
})
}
}

func BenchmarkCoverSCP(b *testing.B) {
for n := 100; n <= 1_000_000; n *= 10 {
tree := interval.NewTree(cmpUintInterval, genUintIvals(n)...)
Expand All @@ -188,6 +219,21 @@ func BenchmarkCoverSCP(b *testing.B) {
}
}

func BenchmarkCoverSCP2(b *testing.B) {
for n := 100; n <= 1_000_000; n *= 10 {
tree := interval.NewTree(cmpUintInterval, gen2UintIvals(n)...)
probe := genUintIvals(1)[0]
name := "In" + intMap[n]

b.Run(name, func(b *testing.B) {
b.ResetTimer()
for n := 0; n < b.N; n++ {
_, _ = tree.CoverSCP(probe)
}
})
}
}

func BenchmarkCoveredBy(b *testing.B) {
for n := 100; n <= 100_000; n *= 10 {
tree := interval.NewTree(cmpUintInterval, genUintIvals(n)...)
Expand All @@ -204,7 +250,7 @@ func BenchmarkCoveredBy(b *testing.B) {
}

func BenchmarkCovers(b *testing.B) {
for n := 100; n <= 100_000; n *= 10 {
for n := 100; n <= 1_000_000; n *= 10 {
tree := interval.NewTree(cmpUintInterval, genUintIvals(n)...)
probe := genUintIvals(1)[0]
name := "In" + intMap[n]
Expand All @@ -218,6 +264,21 @@ func BenchmarkCovers(b *testing.B) {
}
}

func BenchmarkCovers2(b *testing.B) {
for n := 100; n <= 1_000_000; n *= 10 {
tree := interval.NewTree(cmpUintInterval, gen2UintIvals(n)...)
probe := genUintIvals(1)[0]
name := "In" + intMap[n]

b.Run(name, func(b *testing.B) {
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = tree.Covers(probe)
}
})
}
}

func BenchmarkPrecededBy(b *testing.B) {
for m := 100; m <= 10_000; m *= 10 {
tree := interval.NewTree(cmpUintInterval, genUintIvals(m)...)
Expand Down Expand Up @@ -249,7 +310,7 @@ func BenchmarkPrecedes(b *testing.B) {
}

func BenchmarkIntersections(b *testing.B) {
for n := 100; n <= 10_000; n *= 10 {
for n := 100; n <= 100_000; n *= 10 {
tree := interval.NewTree(cmpUintInterval, genUintIvals(n)...)
probe := genUintIvals(1)[0]
name := "In" + intMap[n]
Expand All @@ -263,6 +324,21 @@ func BenchmarkIntersections(b *testing.B) {
}
}

func BenchmarkIntersections2(b *testing.B) {
for n := 100; n <= 100_000; n *= 10 {
tree := interval.NewTree(cmpUintInterval, gen2UintIvals(n)...)
probe := genUintIvals(1)[0]
name := "In" + intMap[n]

b.Run(name, func(b *testing.B) {
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = tree.Intersections(probe)
}
})
}
}

func BenchmarkMin(b *testing.B) {
for n := 100; n <= 1_000_000; n *= 10 {
ivals := genUintIvals(n)
Expand Down
18 changes: 16 additions & 2 deletions treap.go
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,14 @@ func (t *Tree[T]) lcp(n *node[T], item T) (result T, ok bool) {
// tree.CoverSCP(ival{6,9}) returns ival{}, false
//
func (t Tree[T]) CoverSCP(item T) (result T, ok bool) {
return t.scp(t.root, item)
l, m, _ := t.split(t.root, item, true)
result, ok = t.scp(l, item)

if !ok && m != nil {
return m.item, ok
}

return result, ok
}

// scp rec-descent
Expand Down Expand Up @@ -462,7 +469,14 @@ func (t *Tree[T]) scp(n *node[T], item T) (result T, ok bool) {
// Covers returns all intervals that cover the item.
// The returned intervals are in sorted order.
func (t Tree[T]) Covers(item T) []T {
return t.covers(t.root, item)
l, m, _ := t.split(t.root, item, true)
result := t.covers(l, item)

if m != nil {
return append(result, m.item)
}

return result
}

// covers rec-descent
Expand Down
78 changes: 75 additions & 3 deletions treap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,17 @@ func genUintIvals(n int) []uintInterval {
return is
}

// random test data
func gen2UintIvals(n int) []uintInterval {
is := make([]uintInterval, n)
for i := 0; i < n; i++ {
a := rand.Int()
b := a + 100
is[i] = makeUintIval(uint(a), uint(b))
}
return is
}

func equals(a, b uintInterval) bool {
return a[0] == b[0] && a[1] == b[1]
}
Expand Down Expand Up @@ -266,7 +277,7 @@ func TestFind(t *testing.T) {
}
}

func TestLookup(t *testing.T) {
func TestCoverLCP(t *testing.T) {
t.Parallel()

for i := 0; i < 100; i++ {
Expand Down Expand Up @@ -318,9 +329,49 @@ func TestLookup(t *testing.T) {
if got, ok := tree1.CoverLCP(item); ok {
t.Errorf("CoverLCP(%v) = %v, want %v", item, got, !ok)
}
}
}

item = uintInterval{7, 7}
want = uintInterval{1, 8}
func TestCoverSCP(t *testing.T) {
t.Parallel()

for i := 0; i < 100; i++ {
// bring some variance into the Treap due to the prio randomness
tree1 := interval.NewTree(cmpUintInterval, ps...)

// ▼
// ├─ 0...6
// │ └─ 0...5
// ├─ 1...8
// │ ├─ 1...7
// │ │ └─ 1...5
// │ │ └─ 1...4
// │ └─ 2...8
// │ ├─ 2...7
// │ └─ 4...8
// │ └─ 6...7
// └─ 7...9

item := uintInterval{7, 7}
want := uintInterval{1, 8}
if got, _ := tree1.CoverSCP(item); got != want {
t.Errorf("CoverSCP(%v) = %v, want %v", item, got, want)
}

item = uintInterval{7, 9}
want = uintInterval{7, 9}
if got, _ := tree1.CoverSCP(item); got != want {
t.Errorf("CoverSCP(%v) = %v, want %v", item, got, want)
}

item = uintInterval{8, 9}
want = uintInterval{7, 9}
if got, _ := tree1.CoverSCP(item); got != want {
t.Errorf("CoverSCP(%v) = %v, want %v", item, got, want)
}

item = uintInterval{0, 6}
want = uintInterval{0, 6}
if got, _ := tree1.CoverSCP(item); got != want {
t.Errorf("CoverSCP(%v) = %v, want %v", item, got, want)
}
Expand All @@ -342,6 +393,11 @@ func TestLookup(t *testing.T) {
t.Errorf("CoverSCP(%v) = %v, want %v", item, ok, false)
}

item = uintInterval{6, 10}
if _, ok := tree1.CoverSCP(item); ok {
t.Errorf("CoverSCP(%v) = %v, want %v", item, ok, false)
}

}
}

Expand Down Expand Up @@ -471,6 +527,14 @@ func TestIntersects(t *testing.T) {
t.Fatalf("Intersects(%v), got: %v, want: %v", item, got, want)
}

item = uintInterval{0, 1}
want = true
got = tree1.Intersects(item)

if got != want {
t.Fatalf("Intersects(%v), got: %v, want: %v", item, got, want)
}

item = uintInterval{1, 1}
want = true
got = tree1.Intersects(item)
Expand All @@ -486,6 +550,14 @@ func TestIntersects(t *testing.T) {
if got != want {
t.Fatalf("Intersects(%v), got: %v, want: %v", item, got, want)
}

item = uintInterval{10, 10}
want = false
got = tree1.Intersects(item)

if got != want {
t.Fatalf("Intersects(%v), got: %v, want: %v", item, got, want)
}
}

func TestIntersections(t *testing.T) {
Expand Down

0 comments on commit 2fd601d

Please sign in to comment.