mirror of
https://github.com/golang/go
synced 2024-11-18 14:04:45 -07:00
container/intsets: Intersects, SubsetOf, SymmetricDifference(With)
Just reading through intsets and decided to knock out a few TODOs. Change-Id: I677dbcc5ff934fbe0f0af09a4741e708a893f8db Reviewed-on: https://go-review.googlesource.com/2733 Reviewed-by: Alan Donovan <adonovan@google.com>
This commit is contained in:
parent
84afeba471
commit
ac8637e9fa
@ -14,8 +14,6 @@
|
|||||||
package intsets // import "golang.org/x/tools/container/intsets"
|
package intsets // import "golang.org/x/tools/container/intsets"
|
||||||
|
|
||||||
// TODO(adonovan):
|
// TODO(adonovan):
|
||||||
// - Add SymmetricDifference(x, y *Sparse), i.e. x ∆ y.
|
|
||||||
// - Add SubsetOf (x∖y=∅) and Intersects (x∩y≠∅) predicates.
|
|
||||||
// - Add InsertAll(...int), RemoveAll(...int)
|
// - Add InsertAll(...int), RemoveAll(...int)
|
||||||
// - Add 'bool changed' results for {Intersection,Difference}With too.
|
// - Add 'bool changed' results for {Intersection,Difference}With too.
|
||||||
//
|
//
|
||||||
@ -485,6 +483,29 @@ func (s *Sparse) Intersection(x, y *Sparse) {
|
|||||||
s.discardTail(sb)
|
s.discardTail(sb)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Intersects reports whether s ∩ x ≠ ∅.
|
||||||
|
func (s *Sparse) Intersects(x *Sparse) bool {
|
||||||
|
sb := s.start()
|
||||||
|
xb := x.start()
|
||||||
|
for sb != &s.root && xb != &x.root {
|
||||||
|
switch {
|
||||||
|
case xb.offset < sb.offset:
|
||||||
|
xb = xb.next
|
||||||
|
case xb.offset > sb.offset:
|
||||||
|
sb = sb.next
|
||||||
|
default:
|
||||||
|
for i := range sb.bits {
|
||||||
|
if sb.bits[i]&xb.bits[i] != 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sb = sb.next
|
||||||
|
xb = xb.next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// UnionWith sets s to the union s ∪ x, and reports whether s grew.
|
// UnionWith sets s to the union s ∪ x, and reports whether s grew.
|
||||||
func (s *Sparse) UnionWith(x *Sparse) bool {
|
func (s *Sparse) UnionWith(x *Sparse) bool {
|
||||||
if s == x {
|
if s == x {
|
||||||
@ -667,6 +688,146 @@ func (s *Sparse) Difference(x, y *Sparse) {
|
|||||||
s.discardTail(sb)
|
s.discardTail(sb)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SymmetricDifferenceWith sets s to the symmetric difference s ∆ x.
|
||||||
|
func (s *Sparse) SymmetricDifferenceWith(x *Sparse) {
|
||||||
|
if s == x {
|
||||||
|
s.Clear()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sb := s.start()
|
||||||
|
xb := x.start()
|
||||||
|
for xb != &x.root && sb != &s.root {
|
||||||
|
switch {
|
||||||
|
case sb.offset < xb.offset:
|
||||||
|
sb = sb.next
|
||||||
|
case xb.offset < sb.offset:
|
||||||
|
nb := s.insertBlockBefore(sb)
|
||||||
|
nb.offset = xb.offset
|
||||||
|
nb.bits = xb.bits
|
||||||
|
xb = xb.next
|
||||||
|
default:
|
||||||
|
var sum word
|
||||||
|
for i := range sb.bits {
|
||||||
|
r := sb.bits[i] ^ xb.bits[i]
|
||||||
|
sb.bits[i] = r
|
||||||
|
sum |= r
|
||||||
|
}
|
||||||
|
sb = sb.next
|
||||||
|
xb = xb.next
|
||||||
|
if sum == 0 {
|
||||||
|
s.removeBlock(sb.prev)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for xb != &x.root { // append the tail of x to s
|
||||||
|
sb = s.insertBlockBefore(sb)
|
||||||
|
sb.offset = xb.offset
|
||||||
|
sb.bits = xb.bits
|
||||||
|
sb = sb.next
|
||||||
|
xb = xb.next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SymmetricDifference sets s to the symmetric difference x ∆ y.
|
||||||
|
func (s *Sparse) SymmetricDifference(x, y *Sparse) {
|
||||||
|
switch {
|
||||||
|
case x == y:
|
||||||
|
s.Clear()
|
||||||
|
return
|
||||||
|
case s == x:
|
||||||
|
s.SymmetricDifferenceWith(y)
|
||||||
|
return
|
||||||
|
case s == y:
|
||||||
|
s.SymmetricDifferenceWith(x)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sb := s.start()
|
||||||
|
xb := x.start()
|
||||||
|
yb := y.start()
|
||||||
|
for xb != &x.root && yb != &y.root {
|
||||||
|
if sb == &s.root {
|
||||||
|
sb = s.insertBlockBefore(sb)
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case yb.offset < xb.offset:
|
||||||
|
sb.offset = yb.offset
|
||||||
|
sb.bits = yb.bits
|
||||||
|
sb = sb.next
|
||||||
|
yb = yb.next
|
||||||
|
case xb.offset < yb.offset:
|
||||||
|
sb.offset = xb.offset
|
||||||
|
sb.bits = xb.bits
|
||||||
|
sb = sb.next
|
||||||
|
xb = xb.next
|
||||||
|
default:
|
||||||
|
var sum word
|
||||||
|
for i := range sb.bits {
|
||||||
|
r := xb.bits[i] ^ yb.bits[i]
|
||||||
|
sb.bits[i] = r
|
||||||
|
sum |= r
|
||||||
|
}
|
||||||
|
if sum != 0 {
|
||||||
|
sb.offset = xb.offset
|
||||||
|
sb = sb.next
|
||||||
|
}
|
||||||
|
xb = xb.next
|
||||||
|
yb = yb.next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for xb != &x.root { // append the tail of x to s
|
||||||
|
if sb == &s.root {
|
||||||
|
sb = s.insertBlockBefore(sb)
|
||||||
|
}
|
||||||
|
sb.offset = xb.offset
|
||||||
|
sb.bits = xb.bits
|
||||||
|
sb = sb.next
|
||||||
|
xb = xb.next
|
||||||
|
}
|
||||||
|
|
||||||
|
for yb != &y.root { // append the tail of y to s
|
||||||
|
if sb == &s.root {
|
||||||
|
sb = s.insertBlockBefore(sb)
|
||||||
|
}
|
||||||
|
sb.offset = yb.offset
|
||||||
|
sb.bits = yb.bits
|
||||||
|
sb = sb.next
|
||||||
|
yb = yb.next
|
||||||
|
}
|
||||||
|
|
||||||
|
s.discardTail(sb)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubsetOf reports whether s ∖ x = ∅.
|
||||||
|
func (s *Sparse) SubsetOf(x *Sparse) bool {
|
||||||
|
if s == x {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
sb := s.start()
|
||||||
|
xb := x.start()
|
||||||
|
for sb != &s.root {
|
||||||
|
switch {
|
||||||
|
case xb == &x.root || xb.offset > sb.offset:
|
||||||
|
return false
|
||||||
|
case xb.offset < sb.offset:
|
||||||
|
xb = xb.next
|
||||||
|
default:
|
||||||
|
for i := range sb.bits {
|
||||||
|
if sb.bits[i]&^xb.bits[i] != 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sb = sb.next
|
||||||
|
xb = xb.next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// Equals reports whether the sets s and t have the same elements.
|
// Equals reports whether the sets s and t have the same elements.
|
||||||
func (s *Sparse) Equals(t *Sparse) bool {
|
func (s *Sparse) Equals(t *Sparse) bool {
|
||||||
if s == t {
|
if s == t {
|
||||||
|
@ -397,6 +397,47 @@ func TestSetOperations(t *testing.T) {
|
|||||||
D.bits.Copy(&X.bits)
|
D.bits.Copy(&X.bits)
|
||||||
D.bits.DifferenceWith(&D.bits)
|
D.bits.DifferenceWith(&D.bits)
|
||||||
D.check(t, "D.DifferenceWith(D)")
|
D.check(t, "D.DifferenceWith(D)")
|
||||||
|
|
||||||
|
// SD.SymmetricDifference(X, Y)
|
||||||
|
SD := makePset()
|
||||||
|
SD.bits.SymmetricDifference(&X.bits, &Y.bits)
|
||||||
|
for n := range X.hash {
|
||||||
|
if !Y.hash[n] {
|
||||||
|
SD.hash[n] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for n := range Y.hash {
|
||||||
|
if !X.hash[n] {
|
||||||
|
SD.hash[n] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SD.check(t, "SD.SymmetricDifference(X, Y)")
|
||||||
|
|
||||||
|
// X.SymmetricDifferenceWith(Y)
|
||||||
|
SD.bits.Copy(&X.bits)
|
||||||
|
SD.bits.SymmetricDifferenceWith(&Y.bits)
|
||||||
|
SD.check(t, "X.SymmetricDifference(Y)")
|
||||||
|
|
||||||
|
// Y.SymmetricDifferenceWith(X)
|
||||||
|
SD.bits.Copy(&Y.bits)
|
||||||
|
SD.bits.SymmetricDifferenceWith(&X.bits)
|
||||||
|
SD.check(t, "Y.SymmetricDifference(X)")
|
||||||
|
|
||||||
|
// SD.SymmetricDifference(X, X)
|
||||||
|
SD.bits.SymmetricDifference(&X.bits, &X.bits)
|
||||||
|
SD.hash = nil
|
||||||
|
SD.check(t, "SD.SymmetricDifference(X, X)")
|
||||||
|
|
||||||
|
// SD.SymmetricDifference(X, Copy(X))
|
||||||
|
X2 := makePset()
|
||||||
|
X2.bits.Copy(&X.bits)
|
||||||
|
SD.bits.SymmetricDifference(&X.bits, &X2.bits)
|
||||||
|
SD.check(t, "SD.SymmetricDifference(X, Copy(X))")
|
||||||
|
|
||||||
|
// Copy(X).SymmetricDifferenceWith(X)
|
||||||
|
SD.bits.Copy(&X.bits)
|
||||||
|
SD.bits.SymmetricDifferenceWith(&X.bits)
|
||||||
|
SD.check(t, "Copy(X).SymmetricDifferenceWith(X)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,6 +458,82 @@ func TestIntersectionWith(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIntersects(t *testing.T) {
|
||||||
|
prng := rand.New(rand.NewSource(0))
|
||||||
|
|
||||||
|
for i := uint(0); i < 12; i++ {
|
||||||
|
X, Y := randomPset(prng, 1<<i), randomPset(prng, 1<<i)
|
||||||
|
x, y := &X.bits, &Y.bits
|
||||||
|
|
||||||
|
// test the slow way
|
||||||
|
var z intsets.Sparse
|
||||||
|
z.Copy(x)
|
||||||
|
z.IntersectionWith(y)
|
||||||
|
|
||||||
|
if got, want := x.Intersects(y), !z.IsEmpty(); got != want {
|
||||||
|
t.Errorf("Intersects: got %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
// make it false
|
||||||
|
a := x.AppendTo(nil)
|
||||||
|
for _, v := range a {
|
||||||
|
y.Remove(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := x.Intersects(y), false; got != want {
|
||||||
|
t.Errorf("Intersects: got %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
// make it true
|
||||||
|
if x.IsEmpty() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
i := prng.Intn(len(a))
|
||||||
|
y.Insert(a[i])
|
||||||
|
|
||||||
|
if got, want := x.Intersects(y), true; got != want {
|
||||||
|
t.Errorf("Intersects: got %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSubsetOf(t *testing.T) {
|
||||||
|
prng := rand.New(rand.NewSource(0))
|
||||||
|
|
||||||
|
for i := uint(0); i < 12; i++ {
|
||||||
|
X, Y := randomPset(prng, 1<<i), randomPset(prng, 1<<i)
|
||||||
|
x, y := &X.bits, &Y.bits
|
||||||
|
|
||||||
|
// test the slow way
|
||||||
|
var z intsets.Sparse
|
||||||
|
z.Copy(x)
|
||||||
|
z.DifferenceWith(y)
|
||||||
|
|
||||||
|
if got, want := x.SubsetOf(y), z.IsEmpty(); got != want {
|
||||||
|
t.Errorf("SubsetOf: got %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
// make it true
|
||||||
|
y.UnionWith(x)
|
||||||
|
|
||||||
|
if got, want := x.SubsetOf(y), true; got != want {
|
||||||
|
t.Errorf("SubsetOf: got %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
// make it false
|
||||||
|
if x.IsEmpty() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
a := x.AppendTo(nil)
|
||||||
|
i := prng.Intn(len(a))
|
||||||
|
y.Remove(a[i])
|
||||||
|
|
||||||
|
if got, want := x.SubsetOf(y), false; got != want {
|
||||||
|
t.Errorf("SubsetOf: got %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestBitString(t *testing.T) {
|
func TestBitString(t *testing.T) {
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
input []int
|
input []int
|
||||||
|
Loading…
Reference in New Issue
Block a user