From aa713e38324651eb3e1c293698d281c8b897e248 Mon Sep 17 00:00:00 2001 From: Todd Gruben Date: Thu, 25 May 2017 10:07:29 -0500 Subject: [PATCH 1/9] add support for bit flip (negate) in roaring --- roaring/roaring.go | 21 +++++++++++++++++++++ roaring/roaring_test.go | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/roaring/roaring.go b/roaring/roaring.go index bb27a4143..21e87ed0f 100644 --- a/roaring/roaring.go +++ b/roaring/roaring.go @@ -673,6 +673,27 @@ func (b *Bitmap) Check() error { return a } +func (b *Bitmap) Flip(start, end uint64) *Bitmap { + result := NewBitmap() + itr := b.Iterator() + itr.Seek(start) + v, eof := itr.Next() + for i := start; i < end; i++ { + if eof { + result.add(i) + } else if v == i { + v, eof = itr.Next() + } else { + result.add(i) + } + } + for !eof { + result.add(v) + v, eof = itr.Next() + } + return result +} + // BitmapInfo represents a point-in-time snapshot of bitmap stats. type BitmapInfo struct { OpN int diff --git a/roaring/roaring_test.go b/roaring/roaring_test.go index 32492d870..619e194e2 100644 --- a/roaring/roaring_test.go +++ b/roaring/roaring_test.go @@ -168,7 +168,48 @@ func TestBitmap_Xor_BitmapBitmap(t *testing.T) { } } +// Ensure bitmap turn on and turn off +func TestBitmap_Fipp_Empty(t *testing.T) { + bm := roaring.NewBitmap() + results := bm.Flip(0, 10) + if n := results.Count(); n != 10 { + t.Fatalf("unexpected n: %d", n) + } + results = results.Flip(0, 10) + if n := results.Count(); n != 0 { + t.Fatalf("unexpected n: %d", n) + } +} +// Test Subrange Flip should not affect bits outside of Range +func TestBitmap_Fipp_Array(t *testing.T) { + bm := roaring.NewBitmap(0, 1, 2, 3, 4, 8, 16, 32, 64, 128, 256, 512, 1024) + results := bm.Flip(0, 5) + if n := results.Count(); n != 8 { + t.Fatalf("unexpected n: %d", n) + } + results = results.Flip(0, 5) + if n := results.Count(); n != 13 { + t.Fatalf("unexpected n: %d", n) + } + +} + +func TestBitmap_Fipp_Bitmap(t *testing.T) { + bm := roaring.NewBitmap() + size := uint64(10000) + for i := uint64(0); i < size; i += 2 { + bm.Add(i) + } + results := bm.Flip(0, size) + if n := results.Count(); n != size/2 { + t.Fatalf("unexpected n: %d", n) + } + results = results.Flip(0, size) //flipping back should be the same + if n := results.Count(); n != size/2 { + t.Fatalf("unexpected n: %d", n) + } +} // Ensure bitmap can return the number of intersecting bits in two bitmaps. func TestBitmap_IntersectionCount_ArrayArray(t *testing.T) { From aa13bbb6ce63b5b05ec37ea235a5ff6a6e412c44 Mon Sep 17 00:00:00 2001 From: Todd Gruben Date: Wed, 31 May 2017 10:40:52 -0500 Subject: [PATCH 2/9] cleaned up comments --- roaring/roaring.go | 1 + roaring/roaring_test.go | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/roaring/roaring.go b/roaring/roaring.go index 21e87ed0f..9b734effe 100644 --- a/roaring/roaring.go +++ b/roaring/roaring.go @@ -673,6 +673,7 @@ func (b *Bitmap) Check() error { return a } +//Perform a logical negate of the bits in the range [start,end]. func (b *Bitmap) Flip(start, end uint64) *Bitmap { result := NewBitmap() itr := b.Iterator() diff --git a/roaring/roaring_test.go b/roaring/roaring_test.go index 619e194e2..3cf3548de 100644 --- a/roaring/roaring_test.go +++ b/roaring/roaring_test.go @@ -168,8 +168,8 @@ func TestBitmap_Xor_BitmapBitmap(t *testing.T) { } } -// Ensure bitmap turn on and turn off -func TestBitmap_Fipp_Empty(t *testing.T) { +// Ensure bitmap contents alternate. +func TestBitmap_Flip_Empty(t *testing.T) { bm := roaring.NewBitmap() results := bm.Flip(0, 10) if n := results.Count(); n != 10 { @@ -182,7 +182,7 @@ func TestBitmap_Fipp_Empty(t *testing.T) { } // Test Subrange Flip should not affect bits outside of Range -func TestBitmap_Fipp_Array(t *testing.T) { +func TestBitmap_Flip_Array(t *testing.T) { bm := roaring.NewBitmap(0, 1, 2, 3, 4, 8, 16, 32, 64, 128, 256, 512, 1024) results := bm.Flip(0, 5) if n := results.Count(); n != 8 { @@ -195,7 +195,7 @@ func TestBitmap_Fipp_Array(t *testing.T) { } -func TestBitmap_Fipp_Bitmap(t *testing.T) { +func TestBitmap_Flip_Bitmap(t *testing.T) { bm := roaring.NewBitmap() size := uint64(10000) for i := uint64(0); i < size; i += 2 { From 649e58253a19bb7e394800173c5457e1dd30b0eb Mon Sep 17 00:00:00 2001 From: Todd Gruben Date: Wed, 31 May 2017 13:58:54 -0500 Subject: [PATCH 3/9] corrected flip prefix;changed flip to inclusive --- roaring/roaring.go | 16 ++++++++++++++-- roaring/roaring_test.go | 36 +++++++++++++++++++++++++++--------- 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/roaring/roaring.go b/roaring/roaring.go index 9343828f5..0e039b970 100644 --- a/roaring/roaring.go +++ b/roaring/roaring.go @@ -16,6 +16,7 @@ package roaring import ( + "bytes" "encoding/binary" "errors" "fmt" @@ -101,6 +102,14 @@ func (b *Bitmap) Add(a ...uint64) (changed bool, err error) { return changed, nil } +func (b *Bitmap) String() string { + var buffer bytes.Buffer + for _, v := range b.Slice() { + buffer.WriteString(fmt.Sprintf("%d ", v)) + } + buffer.WriteString("\n") + return buffer.String() +} func (b *Bitmap) add(v uint64) bool { hb := highbits(v) @@ -710,9 +719,12 @@ func (b *Bitmap) Check() error { func (b *Bitmap) Flip(start, end uint64) *Bitmap { result := NewBitmap() itr := b.Iterator() - itr.Seek(start) v, eof := itr.Next() - for i := start; i < end; i++ { + for v < start && !eof { + result.add(v) + v, eof = itr.Next() + } + for i := start; i <= end; i++ { if eof { result.add(i) } else if v == i { diff --git a/roaring/roaring_test.go b/roaring/roaring_test.go index eb5f912c6..c1d162551 100644 --- a/roaring/roaring_test.go +++ b/roaring/roaring_test.go @@ -203,7 +203,7 @@ func TestBitmap_Xor_BitmapBitmap(t *testing.T) { func TestBitmap_Flip_Empty(t *testing.T) { bm := roaring.NewBitmap() results := bm.Flip(0, 10) - if n := results.Count(); n != 10 { + if n := results.Count(); n != 11 { t.Fatalf("unexpected n: %d", n) } results = results.Flip(0, 10) @@ -215,13 +215,13 @@ func TestBitmap_Flip_Empty(t *testing.T) { // Test Subrange Flip should not affect bits outside of Range func TestBitmap_Flip_Array(t *testing.T) { bm := roaring.NewBitmap(0, 1, 2, 3, 4, 8, 16, 32, 64, 128, 256, 512, 1024) - results := bm.Flip(0, 5) - if n := results.Count(); n != 8 { - t.Fatalf("unexpected n: %d", n) + results := bm.Flip(0, 4) + if !reflect.DeepEqual(results.Slice(), []uint64{8, 16, 32, 64, 128, 256, 512, 1024}) { + t.Fatalf("unexpected %s ", results.String()) } - results = results.Flip(0, 5) - if n := results.Count(); n != 13 { - t.Fatalf("unexpected n: %d", n) + results = results.Flip(0, 4) + if !reflect.DeepEqual(results.Slice(), []uint64{0, 1, 2, 3, 4, 8, 16, 32, 64, 128, 256, 512, 1024}) { + t.Fatalf("unexpected %s ", results.String()) } } @@ -232,16 +232,34 @@ func TestBitmap_Flip_Bitmap(t *testing.T) { for i := uint64(0); i < size; i += 2 { bm.Add(i) } - results := bm.Flip(0, size) + results := bm.Flip(0, size-1) if n := results.Count(); n != size/2 { t.Fatalf("unexpected n: %d", n) } - results = results.Flip(0, size) //flipping back should be the same + results = results.Flip(0, size-1) //flipping back should be the same if n := results.Count(); n != size/2 { t.Fatalf("unexpected n: %d", n) } } +func TestBitmap_Flip_After(t *testing.T) { + bm := roaring.NewBitmap(0, 2, 4, 8) + results := bm.Flip(9, 10) + + if !reflect.DeepEqual(results.Slice(), []uint64{0, 2, 4, 8, 9, 10}) { + t.Fatalf("unexpected %s ", results.String()) + } + results = results.Flip(0, 1) + if !reflect.DeepEqual(results.Slice(), []uint64{1, 2, 4, 8, 9, 10}) { + t.Fatalf("unexpected %s ", results.String()) + } + results = results.Flip(4, 8) + if !reflect.DeepEqual(results.Slice(), []uint64{1, 2, 5, 6, 7, 9, 10}) { + t.Fatalf("unexpected %s ", results.String()) + } + +} + // Ensure bitmap can return the number of intersecting bits in two bitmaps. func TestBitmap_IntersectionCount_ArrayArray(t *testing.T) { bm0 := roaring.NewBitmap(0, 1000001, 1000002, 1000003) From 7382428f38c7bf11fb584bf2bb0834a3ddd10cd6 Mon Sep 17 00:00:00 2001 From: Todd Gruben Date: Wed, 31 May 2017 15:01:48 -0500 Subject: [PATCH 4/9] clensed String method;added documentation for tests --- roaring/roaring.go | 9 +++++++-- roaring/roaring_test.go | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/roaring/roaring.go b/roaring/roaring.go index 0e039b970..67ca9ebd6 100644 --- a/roaring/roaring.go +++ b/roaring/roaring.go @@ -104,10 +104,12 @@ func (b *Bitmap) Add(a ...uint64) (changed bool, err error) { } func (b *Bitmap) String() string { var buffer bytes.Buffer - for _, v := range b.Slice() { + for i, v := range b.Slice() { buffer.WriteString(fmt.Sprintf("%d ", v)) + if i > 0 { + buffer.WriteString(" ") + } } - buffer.WriteString("\n") return buffer.String() } @@ -720,10 +722,12 @@ func (b *Bitmap) Flip(start, end uint64) *Bitmap { result := NewBitmap() itr := b.Iterator() v, eof := itr.Next() + //copy over previous bits. for v < start && !eof { result.add(v) v, eof = itr.Next() } + //flip bits in range . for i := start; i <= end; i++ { if eof { result.add(i) @@ -733,6 +737,7 @@ func (b *Bitmap) Flip(start, end uint64) *Bitmap { result.add(i) } } + //add remaining. for !eof { result.add(v) v, eof = itr.Next() diff --git a/roaring/roaring_test.go b/roaring/roaring_test.go index c1d162551..53394d93b 100644 --- a/roaring/roaring_test.go +++ b/roaring/roaring_test.go @@ -226,6 +226,7 @@ func TestBitmap_Flip_Array(t *testing.T) { } +// Ensure Flip works with underlying Bitmap container. func TestBitmap_Flip_Bitmap(t *testing.T) { bm := roaring.NewBitmap() size := uint64(10000) @@ -242,6 +243,7 @@ func TestBitmap_Flip_Bitmap(t *testing.T) { } } +// Verify Flip works correctly with in different regions of bitmap, beginning, middle, and end. func TestBitmap_Flip_After(t *testing.T) { bm := roaring.NewBitmap(0, 2, 4, 8) results := bm.Flip(9, 10) From e12fdb69a19e6f387ca192d37e2dbe9876fa8280 Mon Sep 17 00:00:00 2001 From: Todd Gruben Date: Wed, 31 May 2017 15:04:33 -0500 Subject: [PATCH 5/9] better String() --- roaring/roaring.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roaring/roaring.go b/roaring/roaring.go index 67ca9ebd6..63b9698d0 100644 --- a/roaring/roaring.go +++ b/roaring/roaring.go @@ -105,10 +105,10 @@ func (b *Bitmap) Add(a ...uint64) (changed bool, err error) { func (b *Bitmap) String() string { var buffer bytes.Buffer for i, v := range b.Slice() { - buffer.WriteString(fmt.Sprintf("%d ", v)) if i > 0 { buffer.WriteString(" ") } + buffer.WriteString(fmt.Sprintf("%d", v)) } return buffer.String() } From f584400330a35b97624e4d718987cc205aaaf029 Mon Sep 17 00:00:00 2001 From: Todd Gruben Date: Wed, 31 May 2017 16:10:48 -0500 Subject: [PATCH 6/9] attempt to conquer weird --- roaring/roaring.go | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/roaring/roaring.go b/roaring/roaring.go index 63b9698d0..9fb66ce1b 100644 --- a/roaring/roaring.go +++ b/roaring/roaring.go @@ -102,17 +102,6 @@ func (b *Bitmap) Add(a ...uint64) (changed bool, err error) { return changed, nil } -func (b *Bitmap) String() string { - var buffer bytes.Buffer - for i, v := range b.Slice() { - if i > 0 { - buffer.WriteString(" ") - } - buffer.WriteString(fmt.Sprintf("%d", v)) - } - return buffer.String() -} - func (b *Bitmap) add(v uint64) bool { hb := highbits(v) i := search64(b.keys, hb) @@ -220,6 +209,19 @@ func (b *Bitmap) CountRange(start, end uint64) (n uint64) { return n } +//Stringify method for debuging. +func (b *Bitmap) String() string { + var buffer bytes.Buffer + for i, v := range b.Slice() { + if i > 0 { + buffer.WriteString(" ") + } + buffer.WriteString(fmt.Sprintf("%d", v)) + } + return buffer.String() +} + + // Slice returns a slice of all integers in the bitmap. func (b *Bitmap) Slice() []uint64 { var a []uint64 From 879e02de8141012467398d5ab710f7eb03e4164a Mon Sep 17 00:00:00 2001 From: Travis Date: Wed, 31 May 2017 16:22:43 -0500 Subject: [PATCH 7/9] fix misspelling and run gofmt --- roaring/roaring.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/roaring/roaring.go b/roaring/roaring.go index 9fb66ce1b..6fc83c91e 100644 --- a/roaring/roaring.go +++ b/roaring/roaring.go @@ -209,7 +209,7 @@ func (b *Bitmap) CountRange(start, end uint64) (n uint64) { return n } -//Stringify method for debuging. +// Stringify method for debugging. func (b *Bitmap) String() string { var buffer bytes.Buffer for i, v := range b.Slice() { @@ -221,7 +221,6 @@ func (b *Bitmap) String() string { return buffer.String() } - // Slice returns a slice of all integers in the bitmap. func (b *Bitmap) Slice() []uint64 { var a []uint64 From ba2b8cd5b17dda49fbb35ca25021826903aef687 Mon Sep 17 00:00:00 2001 From: Todd Gruben Date: Thu, 1 Jun 2017 10:03:23 -0500 Subject: [PATCH 8/9] removed String method upon discovery of %v --- roaring/roaring.go | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/roaring/roaring.go b/roaring/roaring.go index 6fc83c91e..d071bfd23 100644 --- a/roaring/roaring.go +++ b/roaring/roaring.go @@ -209,18 +209,6 @@ func (b *Bitmap) CountRange(start, end uint64) (n uint64) { return n } -// Stringify method for debugging. -func (b *Bitmap) String() string { - var buffer bytes.Buffer - for i, v := range b.Slice() { - if i > 0 { - buffer.WriteString(" ") - } - buffer.WriteString(fmt.Sprintf("%d", v)) - } - return buffer.String() -} - // Slice returns a slice of all integers in the bitmap. func (b *Bitmap) Slice() []uint64 { var a []uint64 From 542d748baf5a7380ba65a7b8b46e477d9a2e4f04 Mon Sep 17 00:00:00 2001 From: Todd Gruben Date: Thu, 1 Jun 2017 10:17:49 -0500 Subject: [PATCH 9/9] corrected tests to no longer use String method --- roaring/roaring.go | 1 - roaring/roaring_test.go | 12 ++++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/roaring/roaring.go b/roaring/roaring.go index d071bfd23..240fdbc33 100644 --- a/roaring/roaring.go +++ b/roaring/roaring.go @@ -16,7 +16,6 @@ package roaring import ( - "bytes" "encoding/binary" "errors" "fmt" diff --git a/roaring/roaring_test.go b/roaring/roaring_test.go index 53394d93b..bd1ef5954 100644 --- a/roaring/roaring_test.go +++ b/roaring/roaring_test.go @@ -15,8 +15,8 @@ package roaring_test import ( - "bytes" "fmt" + "bytes" "math" "math/rand" "reflect" @@ -217,11 +217,11 @@ func TestBitmap_Flip_Array(t *testing.T) { bm := roaring.NewBitmap(0, 1, 2, 3, 4, 8, 16, 32, 64, 128, 256, 512, 1024) results := bm.Flip(0, 4) if !reflect.DeepEqual(results.Slice(), []uint64{8, 16, 32, 64, 128, 256, 512, 1024}) { - t.Fatalf("unexpected %s ", results.String()) + t.Fatalf("unexpected %v ", results.Slice()) } results = results.Flip(0, 4) if !reflect.DeepEqual(results.Slice(), []uint64{0, 1, 2, 3, 4, 8, 16, 32, 64, 128, 256, 512, 1024}) { - t.Fatalf("unexpected %s ", results.String()) + t.Fatalf("unexpected %v ", results.Slice()) } } @@ -249,15 +249,15 @@ func TestBitmap_Flip_After(t *testing.T) { results := bm.Flip(9, 10) if !reflect.DeepEqual(results.Slice(), []uint64{0, 2, 4, 8, 9, 10}) { - t.Fatalf("unexpected %s ", results.String()) + t.Fatalf("unexpected %v ", results.Slice()) } results = results.Flip(0, 1) if !reflect.DeepEqual(results.Slice(), []uint64{1, 2, 4, 8, 9, 10}) { - t.Fatalf("unexpected %s ", results.String()) + t.Fatalf("unexpected %v ", results.Slice()) } results = results.Flip(4, 8) if !reflect.DeepEqual(results.Slice(), []uint64{1, 2, 5, 6, 7, 9, 10}) { - t.Fatalf("unexpected %s ", results.String()) + t.Fatalf("unexpected %v ", results.Slice()) } }