1
2
3
4
5 package intsets_test
6
7 import (
8 "fmt"
9 "log"
10 "math/rand"
11 "sort"
12 "strings"
13 "testing"
14
15 "golang.org/x/tools/container/intsets"
16 )
17
18 func TestBasics(t *testing.T) {
19 var s intsets.Sparse
20 if len := s.Len(); len != 0 {
21 t.Errorf("Len({}): got %d, want 0", len)
22 }
23 if s := s.String(); s != "{}" {
24 t.Errorf("String({}): got %q, want \"{}\"", s)
25 }
26 if s.Has(3) {
27 t.Errorf("Has(3): got true, want false")
28 }
29 if err := s.Check(); err != nil {
30 t.Error(err)
31 }
32
33 if !s.Insert(3) {
34 t.Errorf("Insert(3): got false, want true")
35 }
36 if max := s.Max(); max != 3 {
37 t.Errorf("Max: got %d, want 3", max)
38 }
39
40 if !s.Insert(435) {
41 t.Errorf("Insert(435): got false, want true")
42 }
43 if s := s.String(); s != "{3 435}" {
44 t.Errorf("String({3 435}): got %q, want \"{3 435}\"", s)
45 }
46 if max := s.Max(); max != 435 {
47 t.Errorf("Max: got %d, want 435", max)
48 }
49 if len := s.Len(); len != 2 {
50 t.Errorf("Len: got %d, want 2", len)
51 }
52
53 if !s.Remove(435) {
54 t.Errorf("Remove(435): got false, want true")
55 }
56 if s := s.String(); s != "{3}" {
57 t.Errorf("String({3}): got %q, want \"{3}\"", s)
58 }
59 }
60
61
62 func TestMoreBasics(t *testing.T) {
63 set := new(intsets.Sparse)
64 set.Insert(456)
65 set.Insert(123)
66 set.Insert(789)
67 if set.Len() != 3 {
68 t.Errorf("%s.Len: got %d, want 3", set, set.Len())
69 }
70 if set.IsEmpty() {
71 t.Errorf("%s.IsEmpty: got true", set)
72 }
73 if !set.Has(123) {
74 t.Errorf("%s.Has(123): got false", set)
75 }
76 if set.Has(1234) {
77 t.Errorf("%s.Has(1234): got true", set)
78 }
79 got := set.AppendTo([]int{-1})
80 if want := []int{-1, 123, 456, 789}; fmt.Sprint(got) != fmt.Sprint(want) {
81 t.Errorf("%s.AppendTo: got %v, want %v", set, got, want)
82 }
83
84 set.Clear()
85
86 if set.Len() != 0 {
87 t.Errorf("Clear: got %d, want 0", set.Len())
88 }
89 if !set.IsEmpty() {
90 t.Errorf("IsEmpty: got false")
91 }
92 if set.Has(123) {
93 t.Errorf("%s.Has: got false", set)
94 }
95 }
96
97 func TestTakeMin(t *testing.T) {
98 var set intsets.Sparse
99 set.Insert(456)
100 set.Insert(123)
101 set.Insert(789)
102 set.Insert(-123)
103 var got int
104 for i, want := range []int{-123, 123, 456, 789} {
105 if !set.TakeMin(&got) || got != want {
106 t.Errorf("TakeMin #%d: got %d, want %d", i, got, want)
107 }
108 }
109 if set.TakeMin(&got) {
110 t.Errorf("%s.TakeMin returned true", &set)
111 }
112 if err := set.Check(); err != nil {
113 t.Fatalf("check: %s: %#v", err, &set)
114 }
115 }
116
117 func TestMinAndMax(t *testing.T) {
118 values := []int{0, 456, 123, 789, -123}
119 wantMax := []int{intsets.MinInt, 456, 456, 789, 789}
120 wantMin := []int{intsets.MaxInt, 456, 123, 123, -123}
121
122 var set intsets.Sparse
123 for i, x := range values {
124 if i != 0 {
125 set.Insert(x)
126 }
127 if got, want := set.Min(), wantMin[i]; got != want {
128 t.Errorf("Min #%d: got %d, want %d", i, got, want)
129 }
130 if got, want := set.Max(), wantMax[i]; got != want {
131 t.Errorf("Max #%d: got %d, want %d", i, got, want)
132 }
133 }
134
135 set.Insert(intsets.MinInt)
136 if got, want := set.Min(), intsets.MinInt; got != want {
137 t.Errorf("Min: got %d, want %d", got, want)
138 }
139
140 set.Insert(intsets.MaxInt)
141 if got, want := set.Max(), intsets.MaxInt; got != want {
142 t.Errorf("Max: got %d, want %d", got, want)
143 }
144 }
145
146 func TestEquals(t *testing.T) {
147 var setX intsets.Sparse
148 setX.Insert(456)
149 setX.Insert(123)
150 setX.Insert(789)
151
152 if !setX.Equals(&setX) {
153 t.Errorf("Equals(%s, %s): got false", &setX, &setX)
154 }
155
156 var setY intsets.Sparse
157 setY.Insert(789)
158 setY.Insert(456)
159 setY.Insert(123)
160
161 if !setX.Equals(&setY) {
162 t.Errorf("Equals(%s, %s): got false", &setX, &setY)
163 }
164
165 setY.Insert(1)
166 if setX.Equals(&setY) {
167 t.Errorf("Equals(%s, %s): got true", &setX, &setY)
168 }
169
170 var empty intsets.Sparse
171 if setX.Equals(&empty) {
172 t.Errorf("Equals(%s, %s): got true", &setX, &empty)
173 }
174
175
176 setY.Remove(123)
177 if setX.Equals(&setY) {
178 t.Errorf("Equals(%s, %s): got true", &setX, &setY)
179 }
180 }
181
182
183
184 type pset struct {
185 hash map[int]bool
186 bits intsets.Sparse
187 }
188
189 func makePset() *pset {
190 return &pset{hash: make(map[int]bool)}
191 }
192
193 func (set *pset) add(n int) {
194 prev := len(set.hash)
195 set.hash[n] = true
196 grewA := len(set.hash) > prev
197
198 grewB := set.bits.Insert(n)
199
200 if grewA != grewB {
201 panic(fmt.Sprintf("add(%d): grewA=%t grewB=%t", n, grewA, grewB))
202 }
203 }
204
205 func (set *pset) remove(n int) {
206 prev := len(set.hash)
207 delete(set.hash, n)
208 shrankA := len(set.hash) < prev
209
210 shrankB := set.bits.Remove(n)
211
212 if shrankA != shrankB {
213 panic(fmt.Sprintf("remove(%d): shrankA=%t shrankB=%t", n, shrankA, shrankB))
214 }
215 }
216
217 func (set *pset) check(t *testing.T, msg string) {
218 var eltsA []int
219 for elt := range set.hash {
220 eltsA = append(eltsA, int(elt))
221 }
222 sort.Ints(eltsA)
223
224 eltsB := set.bits.AppendTo(nil)
225
226 if a, b := fmt.Sprint(eltsA), fmt.Sprint(eltsB); a != b {
227 t.Errorf("check(%s): hash=%s bits=%s (%s)", msg, a, b, &set.bits)
228 }
229
230 if err := set.bits.Check(); err != nil {
231 t.Fatalf("Check(%s): %s: %#v", msg, err, &set.bits)
232 }
233 }
234
235
236 func randomPset(prng *rand.Rand, maxSize int) *pset {
237 set := makePset()
238 size := int(prng.Int()) % maxSize
239 for i := 0; i < size; i++ {
240
241
242 n := int(prng.Int()) % 10000
243 set.add(n)
244 }
245 return set
246 }
247
248
249
250 func TestRandomMutations(t *testing.T) {
251 const debug = false
252
253 set := makePset()
254 prng := rand.New(rand.NewSource(0))
255 for i := 0; i < 10000; i++ {
256 n := int(prng.Int())%2000 - 1000
257 if i%2 == 0 {
258 if debug {
259 log.Printf("add %d", n)
260 }
261 set.add(n)
262 } else {
263 if debug {
264 log.Printf("remove %d", n)
265 }
266 set.remove(n)
267 }
268 if debug {
269 set.check(t, "post mutation")
270 }
271 }
272 set.check(t, "final")
273 if debug {
274 log.Print(&set.bits)
275 }
276 }
277
278 func TestLowerBound(t *testing.T) {
279
280 prng := rand.New(rand.NewSource(0))
281 for i := uint(0); i < 12; i++ {
282 x := randomPset(prng, 1<<i)
283 for j := 0; j < 10000; j++ {
284 found := intsets.MaxInt
285 for e := range x.hash {
286 if e >= j && e < found {
287 found = e
288 }
289 }
290 if res := x.bits.LowerBound(j); res != found {
291 t.Errorf("%s: LowerBound(%d)=%d, expected %d", &x.bits, j, res, found)
292 }
293 }
294 }
295 }
296
297
298 func TestSetOperations(t *testing.T) {
299 prng := rand.New(rand.NewSource(0))
300
301
302
303
304
305 for i := uint(0); i < 12; i++ {
306 X := randomPset(prng, 1<<i)
307 Y := randomPset(prng, 1<<i)
308
309
310
311
312 C := makePset()
313 C.bits.Copy(&Y.bits)
314 C.bits.Copy(&X.bits)
315 C.hash = X.hash
316 C.check(t, "C.Copy(X)")
317 C.bits.Copy(&C.bits)
318 C.check(t, "C.Copy(C)")
319
320
321 U := makePset()
322 U.bits.Union(&X.bits, &Y.bits)
323 for n := range X.hash {
324 U.hash[n] = true
325 }
326 for n := range Y.hash {
327 U.hash[n] = true
328 }
329 U.check(t, "U.Union(X, Y)")
330
331
332 U.bits.Union(&X.bits, &X.bits)
333 U.hash = X.hash
334 U.check(t, "U.Union(X, X)")
335
336
337 U = makePset()
338 U.bits.Copy(&X.bits)
339 U.bits.Union(&U.bits, &Y.bits)
340 for n := range X.hash {
341 U.hash[n] = true
342 }
343 for n := range Y.hash {
344 U.hash[n] = true
345 }
346 U.check(t, "U.Union(U, Y)")
347
348
349 U.bits.Copy(&Y.bits)
350 U.bits.Union(&X.bits, &U.bits)
351 U.check(t, "U.Union(X, U)")
352
353
354 U.bits.UnionWith(&U.bits)
355 U.check(t, "U.UnionWith(U)")
356
357
358 I := makePset()
359 I.bits.Intersection(&X.bits, &Y.bits)
360 for n := range X.hash {
361 if Y.hash[n] {
362 I.hash[n] = true
363 }
364 }
365 I.check(t, "I.Intersection(X, Y)")
366
367
368 I.bits.Intersection(&X.bits, &X.bits)
369 I.hash = X.hash
370 I.check(t, "I.Intersection(X, X)")
371
372
373 I.bits.Intersection(&I.bits, &X.bits)
374 I.check(t, "I.Intersection(I, X)")
375
376
377 I.bits.Intersection(&X.bits, &I.bits)
378 I.check(t, "I.Intersection(X, I)")
379
380
381 I.bits.Intersection(&I.bits, &I.bits)
382 I.check(t, "I.Intersection(I, I)")
383
384
385 D := makePset()
386 D.bits.Difference(&X.bits, &Y.bits)
387 for n := range X.hash {
388 if !Y.hash[n] {
389 D.hash[n] = true
390 }
391 }
392 D.check(t, "D.Difference(X, Y)")
393
394
395 D.bits.Copy(&X.bits)
396 D.bits.Difference(&D.bits, &Y.bits)
397 D.check(t, "D.Difference(D, Y)")
398
399
400 D.bits.Copy(&X.bits)
401 D.bits.Difference(&Y.bits, &D.bits)
402 D.hash = make(map[int]bool)
403 for n := range Y.hash {
404 if !X.hash[n] {
405 D.hash[n] = true
406 }
407 }
408 D.check(t, "D.Difference(Y, D)")
409
410
411 D.bits.Difference(&X.bits, &X.bits)
412 D.hash = nil
413 D.check(t, "D.Difference(X, X)")
414
415
416 D.bits.Copy(&X.bits)
417 D.bits.DifferenceWith(&D.bits)
418 D.check(t, "D.DifferenceWith(D)")
419
420
421 SD := makePset()
422 SD.bits.SymmetricDifference(&X.bits, &Y.bits)
423 for n := range X.hash {
424 if !Y.hash[n] {
425 SD.hash[n] = true
426 }
427 }
428 for n := range Y.hash {
429 if !X.hash[n] {
430 SD.hash[n] = true
431 }
432 }
433 SD.check(t, "SD.SymmetricDifference(X, Y)")
434
435
436 SD.bits.Copy(&X.bits)
437 SD.bits.SymmetricDifferenceWith(&Y.bits)
438 SD.check(t, "X.SymmetricDifference(Y)")
439
440
441 SD.bits.Copy(&Y.bits)
442 SD.bits.SymmetricDifferenceWith(&X.bits)
443 SD.check(t, "Y.SymmetricDifference(X)")
444
445
446 SD.bits.SymmetricDifference(&X.bits, &X.bits)
447 SD.hash = nil
448 SD.check(t, "SD.SymmetricDifference(X, X)")
449
450
451 X2 := makePset()
452 X2.bits.Copy(&X.bits)
453 SD.bits.SymmetricDifference(&X.bits, &X2.bits)
454 SD.check(t, "SD.SymmetricDifference(X, Copy(X))")
455
456
457 SD.bits.Copy(&X.bits)
458 SD.bits.SymmetricDifferenceWith(&X.bits)
459 SD.check(t, "Copy(X).SymmetricDifferenceWith(X)")
460 }
461 }
462
463
464 func TestUnionWithChanged(t *testing.T) {
465 setOf := func(elems ...int) *intsets.Sparse {
466 s := new(intsets.Sparse)
467 for _, elem := range elems {
468 s.Insert(elem)
469 }
470 return s
471 }
472
473 checkUnionWith := func(x, y *intsets.Sparse) {
474 xstr := x.String()
475 prelen := x.Len()
476 changed := x.UnionWith(y)
477 if (x.Len() > prelen) != changed {
478 t.Errorf("%s.UnionWith(%s) => %s, changed=%t", xstr, y, x, changed)
479 }
480 }
481
482
483
484
485
486 checkUnionWith(setOf(1, 2), setOf(1, 2))
487 checkUnionWith(setOf(1, 2, 3), setOf(1, 2))
488 checkUnionWith(setOf(1, 2), setOf(1, 2, 3))
489 checkUnionWith(setOf(1, 2), setOf())
490
491
492 checkUnionWith(setOf(1, 1000000), setOf(1, 1000000))
493 checkUnionWith(setOf(1, 2, 1000000), setOf(1, 2))
494 checkUnionWith(setOf(1, 2), setOf(1, 2, 1000000))
495 checkUnionWith(setOf(1, 1000000), setOf())
496 }
497
498 func TestIntersectionWith(t *testing.T) {
499
500
501
502 var X, Y intsets.Sparse
503 X.Insert(1)
504 X.Insert(1000)
505 X.Insert(8000)
506 Y.Insert(1)
507 Y.Insert(2000)
508 Y.Insert(4000)
509 X.IntersectionWith(&Y)
510 if got, want := X.String(), "{1}"; got != want {
511 t.Errorf("IntersectionWith: got %s, want %s", got, want)
512 }
513 }
514
515 func TestIntersects(t *testing.T) {
516 prng := rand.New(rand.NewSource(0))
517
518 for i := uint(0); i < 12; i++ {
519 X, Y := randomPset(prng, 1<<i), randomPset(prng, 1<<i)
520 x, y := &X.bits, &Y.bits
521
522
523 var z intsets.Sparse
524 z.Copy(x)
525 z.IntersectionWith(y)
526
527 if got, want := x.Intersects(y), !z.IsEmpty(); got != want {
528 t.Errorf("Intersects(%s, %s): got %v, want %v (%s)", x, y, got, want, &z)
529 }
530
531
532 a := x.AppendTo(nil)
533 for _, v := range a {
534 y.Remove(v)
535 }
536
537 if got, want := x.Intersects(y), false; got != want {
538 t.Errorf("Intersects: got %v, want %v", got, want)
539 }
540
541
542 if x.IsEmpty() {
543 continue
544 }
545 i := prng.Intn(len(a))
546 y.Insert(a[i])
547
548 if got, want := x.Intersects(y), true; got != want {
549 t.Errorf("Intersects: got %v, want %v", got, want)
550 }
551 }
552 }
553
554 func TestSubsetOf(t *testing.T) {
555 prng := rand.New(rand.NewSource(0))
556
557 for i := uint(0); i < 12; i++ {
558 X, Y := randomPset(prng, 1<<i), randomPset(prng, 1<<i)
559 x, y := &X.bits, &Y.bits
560
561
562 var z intsets.Sparse
563 z.Copy(x)
564 z.DifferenceWith(y)
565
566 if got, want := x.SubsetOf(y), z.IsEmpty(); got != want {
567 t.Errorf("SubsetOf: got %v, want %v", got, want)
568 }
569
570
571 y.UnionWith(x)
572
573 if got, want := x.SubsetOf(y), true; got != want {
574 t.Errorf("SubsetOf: got %v, want %v", got, want)
575 }
576
577
578 if x.IsEmpty() {
579 continue
580 }
581 a := x.AppendTo(nil)
582 i := prng.Intn(len(a))
583 y.Remove(a[i])
584
585 if got, want := x.SubsetOf(y), false; got != want {
586 t.Errorf("SubsetOf: got %v, want %v", got, want)
587 }
588 }
589 }
590
591 func TestBitString(t *testing.T) {
592 for _, test := range []struct {
593 input []int
594 want string
595 }{
596 {nil, "0"},
597 {[]int{0}, "1"},
598 {[]int{0, 4, 5}, "110001"},
599 {[]int{0, 7, 177}, "1" + strings.Repeat("0", 169) + "10000001"},
600 {[]int{-3, 0, 4, 5}, "110001.001"},
601 {[]int{-3}, "0.001"},
602 } {
603 var set intsets.Sparse
604 for _, x := range test.input {
605 set.Insert(x)
606 }
607 if got := set.BitString(); got != test.want {
608 t.Errorf("BitString(%s) = %s, want %s", set.String(), got, test.want)
609 }
610 }
611 }
612
613 func TestFailFastOnShallowCopy(t *testing.T) {
614 var x intsets.Sparse
615 x.Insert(1)
616
617 y := x
618 defer func() {
619 got := fmt.Sprint(recover())
620 want := "interface conversion: interface {} is nil, not intsets.to_copy_a_sparse_you_must_call_its_Copy_method"
621 if got != want {
622 t.Errorf("shallow copy: recover() = %q, want %q", got, want)
623 }
624 }()
625 _ = y.String()
626 t.Error("didn't panic as expected")
627 }
628
629
630
631
632
633
634
635
636 func benchmarkInsertProbeSparse(b *testing.B, size, spread int) {
637 prng := rand.New(rand.NewSource(0))
638
639
640 insert := make([]int, size)
641 probe := make([]int, size*2)
642 for i := range insert {
643 insert[i] = prng.Int() % spread
644 }
645 for i := range probe {
646 probe[i] = prng.Int() % spread
647 }
648
649 b.ResetTimer()
650 var x intsets.Sparse
651 for tries := 0; tries < b.N; tries++ {
652 x.Clear()
653 for _, n := range insert {
654 x.Insert(n)
655 }
656 hits := 0
657 for _, n := range probe {
658 if x.Has(n) {
659 hits++
660 }
661 }
662
663 if hits > len(probe) {
664 b.Fatalf("%d hits, only %d probes", hits, len(probe))
665 }
666 }
667 }
668
669 func BenchmarkInsertProbeSparse_2_10(b *testing.B) {
670 benchmarkInsertProbeSparse(b, 2, 10)
671 }
672
673 func BenchmarkInsertProbeSparse_10_10(b *testing.B) {
674 benchmarkInsertProbeSparse(b, 10, 10)
675 }
676
677 func BenchmarkInsertProbeSparse_10_1000(b *testing.B) {
678 benchmarkInsertProbeSparse(b, 10, 1000)
679 }
680
681 func BenchmarkInsertProbeSparse_100_100(b *testing.B) {
682 benchmarkInsertProbeSparse(b, 100, 100)
683 }
684
685 func BenchmarkInsertProbeSparse_100_10000(b *testing.B) {
686 benchmarkInsertProbeSparse(b, 100, 1000)
687 }
688
689 func BenchmarkUnionDifferenceSparse(b *testing.B) {
690 prng := rand.New(rand.NewSource(0))
691 for tries := 0; tries < b.N; tries++ {
692 var x, y, z intsets.Sparse
693 for i := 0; i < 1000; i++ {
694 n := int(prng.Int()) % 100000
695 if i%2 == 0 {
696 x.Insert(n)
697 } else {
698 y.Insert(n)
699 }
700 }
701 z.Union(&x, &y)
702 z.Difference(&x, &y)
703 }
704 }
705
706 func BenchmarkUnionDifferenceHashTable(b *testing.B) {
707 prng := rand.New(rand.NewSource(0))
708 for tries := 0; tries < b.N; tries++ {
709 x, y, z := make(map[int]bool), make(map[int]bool), make(map[int]bool)
710 for i := 0; i < 1000; i++ {
711 n := int(prng.Int()) % 100000
712 if i%2 == 0 {
713 x[n] = true
714 } else {
715 y[n] = true
716 }
717 }
718
719 for n := range x {
720 z[n] = true
721 }
722 for n := range y {
723 z[n] = true
724 }
725
726 z = make(map[int]bool)
727 for n := range y {
728 if !x[n] {
729 z[n] = true
730 }
731 }
732 }
733 }
734
735 func BenchmarkAppendTo(b *testing.B) {
736 prng := rand.New(rand.NewSource(0))
737 var x intsets.Sparse
738 for i := 0; i < 1000; i++ {
739 x.Insert(int(prng.Int()) % 10000)
740 }
741 var space [1000]int
742 for tries := 0; tries < b.N; tries++ {
743 x.AppendTo(space[:0])
744 }
745 }
746
View as plain text