github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/tools/container/intsets/sparse_test.go (about) 1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 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 // Insert, Len, IsEmpty, Hash, Clear, AppendTo. 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} // elt 0 => empty set 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 // Edge case: some block (with offset=0) appears in X but not Y. 176 setY.Remove(123) 177 if setX.Equals(&setY) { 178 t.Errorf("Equals(%s, %s): got true", &setX, &setY) 179 } 180 } 181 182 // A pset is a parallel implementation of a set using both an intsets.Sparse 183 // and a built-in hash map. 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 // randomPset returns a parallel set of random size and elements. 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 // TODO(adonovan): benchmark how performance varies 241 // with this sparsity parameter. 242 n := int(prng.Int()) % 10000 243 set.add(n) 244 } 245 return set 246 } 247 248 // TestRandomMutations performs the same random adds/removes on two 249 // set implementations and ensures that they compute the same result. 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 // TestSetOperations exercises classic set operations: ∩ , ∪, \. 279 func TestSetOperations(t *testing.T) { 280 prng := rand.New(rand.NewSource(0)) 281 282 // Use random sets of sizes from 0 to about 1000. 283 // For each operator, we test variations such as 284 // Z.op(X, Y), Z.op(X, Z) and Z.op(Z, Y) to exercise 285 // the degenerate cases of each method implementation. 286 for i := uint(0); i < 12; i++ { 287 X := randomPset(prng, 1<<i) 288 Y := randomPset(prng, 1<<i) 289 290 // TODO(adonovan): minimise dependencies between stanzas below. 291 292 // Copy(X) 293 C := makePset() 294 C.bits.Copy(&Y.bits) // no effect on result 295 C.bits.Copy(&X.bits) 296 C.hash = X.hash 297 C.check(t, "C.Copy(X)") 298 C.bits.Copy(&C.bits) 299 C.check(t, "C.Copy(C)") 300 301 // U.Union(X, Y) 302 U := makePset() 303 U.bits.Union(&X.bits, &Y.bits) 304 for n := range X.hash { 305 U.hash[n] = true 306 } 307 for n := range Y.hash { 308 U.hash[n] = true 309 } 310 U.check(t, "U.Union(X, Y)") 311 312 // U.Union(X, X) 313 U.bits.Union(&X.bits, &X.bits) 314 U.hash = X.hash 315 U.check(t, "U.Union(X, X)") 316 317 // U.Union(U, Y) 318 U = makePset() 319 U.bits.Copy(&X.bits) 320 U.bits.Union(&U.bits, &Y.bits) 321 for n := range X.hash { 322 U.hash[n] = true 323 } 324 for n := range Y.hash { 325 U.hash[n] = true 326 } 327 U.check(t, "U.Union(U, Y)") 328 329 // U.Union(X, U) 330 U.bits.Copy(&Y.bits) 331 U.bits.Union(&X.bits, &U.bits) 332 U.check(t, "U.Union(X, U)") 333 334 // U.UnionWith(U) 335 U.bits.UnionWith(&U.bits) 336 U.check(t, "U.UnionWith(U)") 337 338 // I.Intersection(X, Y) 339 I := makePset() 340 I.bits.Intersection(&X.bits, &Y.bits) 341 for n := range X.hash { 342 if Y.hash[n] { 343 I.hash[n] = true 344 } 345 } 346 I.check(t, "I.Intersection(X, Y)") 347 348 // I.Intersection(X, X) 349 I.bits.Intersection(&X.bits, &X.bits) 350 I.hash = X.hash 351 I.check(t, "I.Intersection(X, X)") 352 353 // I.Intersection(I, X) 354 I.bits.Intersection(&I.bits, &X.bits) 355 I.check(t, "I.Intersection(I, X)") 356 357 // I.Intersection(X, I) 358 I.bits.Intersection(&X.bits, &I.bits) 359 I.check(t, "I.Intersection(X, I)") 360 361 // I.Intersection(I, I) 362 I.bits.Intersection(&I.bits, &I.bits) 363 I.check(t, "I.Intersection(I, I)") 364 365 // D.Difference(X, Y) 366 D := makePset() 367 D.bits.Difference(&X.bits, &Y.bits) 368 for n := range X.hash { 369 if !Y.hash[n] { 370 D.hash[n] = true 371 } 372 } 373 D.check(t, "D.Difference(X, Y)") 374 375 // D.Difference(D, Y) 376 D.bits.Copy(&X.bits) 377 D.bits.Difference(&D.bits, &Y.bits) 378 D.check(t, "D.Difference(D, Y)") 379 380 // D.Difference(Y, D) 381 D.bits.Copy(&X.bits) 382 D.bits.Difference(&Y.bits, &D.bits) 383 D.hash = make(map[int]bool) 384 for n := range Y.hash { 385 if !X.hash[n] { 386 D.hash[n] = true 387 } 388 } 389 D.check(t, "D.Difference(Y, D)") 390 391 // D.Difference(X, X) 392 D.bits.Difference(&X.bits, &X.bits) 393 D.hash = nil 394 D.check(t, "D.Difference(X, X)") 395 396 // D.DifferenceWith(D) 397 D.bits.Copy(&X.bits) 398 D.bits.DifferenceWith(&D.bits) 399 D.check(t, "D.DifferenceWith(D)") 400 401 // SD.SymmetricDifference(X, Y) 402 SD := makePset() 403 SD.bits.SymmetricDifference(&X.bits, &Y.bits) 404 for n := range X.hash { 405 if !Y.hash[n] { 406 SD.hash[n] = true 407 } 408 } 409 for n := range Y.hash { 410 if !X.hash[n] { 411 SD.hash[n] = true 412 } 413 } 414 SD.check(t, "SD.SymmetricDifference(X, Y)") 415 416 // X.SymmetricDifferenceWith(Y) 417 SD.bits.Copy(&X.bits) 418 SD.bits.SymmetricDifferenceWith(&Y.bits) 419 SD.check(t, "X.SymmetricDifference(Y)") 420 421 // Y.SymmetricDifferenceWith(X) 422 SD.bits.Copy(&Y.bits) 423 SD.bits.SymmetricDifferenceWith(&X.bits) 424 SD.check(t, "Y.SymmetricDifference(X)") 425 426 // SD.SymmetricDifference(X, X) 427 SD.bits.SymmetricDifference(&X.bits, &X.bits) 428 SD.hash = nil 429 SD.check(t, "SD.SymmetricDifference(X, X)") 430 431 // SD.SymmetricDifference(X, Copy(X)) 432 X2 := makePset() 433 X2.bits.Copy(&X.bits) 434 SD.bits.SymmetricDifference(&X.bits, &X2.bits) 435 SD.check(t, "SD.SymmetricDifference(X, Copy(X))") 436 437 // Copy(X).SymmetricDifferenceWith(X) 438 SD.bits.Copy(&X.bits) 439 SD.bits.SymmetricDifferenceWith(&X.bits) 440 SD.check(t, "Copy(X).SymmetricDifferenceWith(X)") 441 } 442 } 443 444 func TestIntersectionWith(t *testing.T) { 445 // Edge cases: the pairs (1,1), (1000,2000), (8000,4000) 446 // exercise the <, >, == cases in IntersectionWith that the 447 // TestSetOperations data is too dense to cover. 448 var X, Y intsets.Sparse 449 X.Insert(1) 450 X.Insert(1000) 451 X.Insert(8000) 452 Y.Insert(1) 453 Y.Insert(2000) 454 Y.Insert(4000) 455 X.IntersectionWith(&Y) 456 if got, want := X.String(), "{1}"; got != want { 457 t.Errorf("IntersectionWith: got %s, want %s", got, want) 458 } 459 } 460 461 func TestIntersects(t *testing.T) { 462 prng := rand.New(rand.NewSource(0)) 463 464 for i := uint(0); i < 12; i++ { 465 X, Y := randomPset(prng, 1<<i), randomPset(prng, 1<<i) 466 x, y := &X.bits, &Y.bits 467 468 // test the slow way 469 var z intsets.Sparse 470 z.Copy(x) 471 z.IntersectionWith(y) 472 473 if got, want := x.Intersects(y), !z.IsEmpty(); got != want { 474 t.Errorf("Intersects: got %v, want %v", got, want) 475 } 476 477 // make it false 478 a := x.AppendTo(nil) 479 for _, v := range a { 480 y.Remove(v) 481 } 482 483 if got, want := x.Intersects(y), false; got != want { 484 t.Errorf("Intersects: got %v, want %v", got, want) 485 } 486 487 // make it true 488 if x.IsEmpty() { 489 continue 490 } 491 i := prng.Intn(len(a)) 492 y.Insert(a[i]) 493 494 if got, want := x.Intersects(y), true; got != want { 495 t.Errorf("Intersects: got %v, want %v", got, want) 496 } 497 } 498 } 499 500 func TestSubsetOf(t *testing.T) { 501 prng := rand.New(rand.NewSource(0)) 502 503 for i := uint(0); i < 12; i++ { 504 X, Y := randomPset(prng, 1<<i), randomPset(prng, 1<<i) 505 x, y := &X.bits, &Y.bits 506 507 // test the slow way 508 var z intsets.Sparse 509 z.Copy(x) 510 z.DifferenceWith(y) 511 512 if got, want := x.SubsetOf(y), z.IsEmpty(); got != want { 513 t.Errorf("SubsetOf: got %v, want %v", got, want) 514 } 515 516 // make it true 517 y.UnionWith(x) 518 519 if got, want := x.SubsetOf(y), true; got != want { 520 t.Errorf("SubsetOf: got %v, want %v", got, want) 521 } 522 523 // make it false 524 if x.IsEmpty() { 525 continue 526 } 527 a := x.AppendTo(nil) 528 i := prng.Intn(len(a)) 529 y.Remove(a[i]) 530 531 if got, want := x.SubsetOf(y), false; got != want { 532 t.Errorf("SubsetOf: got %v, want %v", got, want) 533 } 534 } 535 } 536 537 func TestBitString(t *testing.T) { 538 for _, test := range []struct { 539 input []int 540 want string 541 }{ 542 {nil, "0"}, 543 {[]int{0}, "1"}, 544 {[]int{0, 4, 5}, "110001"}, 545 {[]int{0, 7, 177}, "1" + strings.Repeat("0", 169) + "10000001"}, 546 {[]int{-3, 0, 4, 5}, "110001.001"}, 547 {[]int{-3}, "0.001"}, 548 } { 549 var set intsets.Sparse 550 for _, x := range test.input { 551 set.Insert(x) 552 } 553 if got := set.BitString(); got != test.want { 554 t.Errorf("BitString(%s) = %s, want %s", set.String(), got, test.want) 555 } 556 } 557 } 558 559 func TestFailFastOnShallowCopy(t *testing.T) { 560 var x intsets.Sparse 561 x.Insert(1) 562 563 y := x // shallow copy (breaks representation invariants) 564 defer func() { 565 got := fmt.Sprint(recover()) 566 want := "A Sparse has been copied without (*Sparse).Copy()" 567 if got != want { 568 t.Errorf("shallow copy: recover() = %q, want %q", got, want) 569 } 570 }() 571 y.String() // panics 572 t.Error("didn't panic as expected") 573 } 574 575 // -- Benchmarks ------------------------------------------------------- 576 577 // TODO(adonovan): 578 // - Add benchmarks of each method. 579 // - Gather set distributions from pointer analysis. 580 // - Measure memory usage. 581 582 func BenchmarkSparseBitVector(b *testing.B) { 583 prng := rand.New(rand.NewSource(0)) 584 for tries := 0; tries < b.N; tries++ { 585 var x, y, z intsets.Sparse 586 for i := 0; i < 1000; i++ { 587 n := int(prng.Int()) % 100000 588 if i%2 == 0 { 589 x.Insert(n) 590 } else { 591 y.Insert(n) 592 } 593 } 594 z.Union(&x, &y) 595 z.Difference(&x, &y) 596 } 597 } 598 599 func BenchmarkHashTable(b *testing.B) { 600 prng := rand.New(rand.NewSource(0)) 601 for tries := 0; tries < b.N; tries++ { 602 x, y, z := make(map[int]bool), make(map[int]bool), make(map[int]bool) 603 for i := 0; i < 1000; i++ { 604 n := int(prng.Int()) % 100000 605 if i%2 == 0 { 606 x[n] = true 607 } else { 608 y[n] = true 609 } 610 } 611 // union 612 for n := range x { 613 z[n] = true 614 } 615 for n := range y { 616 z[n] = true 617 } 618 // difference 619 z = make(map[int]bool) 620 for n := range y { 621 if !x[n] { 622 z[n] = true 623 } 624 } 625 } 626 } 627 628 func BenchmarkAppendTo(b *testing.B) { 629 prng := rand.New(rand.NewSource(0)) 630 var x intsets.Sparse 631 for i := 0; i < 1000; i++ { 632 x.Insert(int(prng.Int()) % 10000) 633 } 634 var space [1000]int 635 for tries := 0; tries < b.N; tries++ { 636 x.AppendTo(space[:0]) 637 } 638 }