github.com/camlistore/go4@v0.0.0-20200104003542-c7e774b10ea0/sort/sort_test.go (about) 1 // Copyright 2009 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 sort_test 6 7 import ( 8 "fmt" 9 "math" 10 "math/rand" 11 "reflect" 12 "strconv" 13 "testing" 14 15 "go4.org/reflectutil" 16 . "go4.org/sort" 17 ) 18 19 var ints = [...]int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586} 20 var float64s = [...]float64{74.3, 59.0, math.Inf(1), 238.2, -784.0, 2.3, math.NaN(), math.NaN(), math.Inf(-1), 9845.768, -959.7485, 905, 7.8, 7.8} 21 var strings = [...]string{"", "Hello", "foo", "bar", "foo", "f00", "%*&^*&^&", "***"} 22 23 func TestSlice(t *testing.T) { 24 s := []int{5, 4, 3, 2, 1} 25 want := []int{1, 2, 3, 4, 5} 26 Slice(s, func(i, j int) bool { return s[i] < s[j] }) 27 if !reflect.DeepEqual(s, want) { 28 t.Errorf("sorted = %v; want %v", s, want) 29 } 30 } 31 32 func TestSortIntSlice(t *testing.T) { 33 data := ints 34 a := IntSlice(data[0:]) 35 Sort(a) 36 if !IsSorted(a) { 37 t.Errorf("sorted %v", ints) 38 t.Errorf(" got %v", data) 39 } 40 } 41 42 func TestSortFloat64Slice(t *testing.T) { 43 data := float64s 44 a := Float64Slice(data[0:]) 45 Sort(a) 46 if !IsSorted(a) { 47 t.Errorf("sorted %v", float64s) 48 t.Errorf(" got %v", data) 49 } 50 } 51 52 func TestSortStringSlice(t *testing.T) { 53 data := strings 54 a := StringSlice(data[0:]) 55 Sort(a) 56 if !IsSorted(a) { 57 t.Errorf("sorted %v", strings) 58 t.Errorf(" got %v", data) 59 } 60 } 61 62 func TestInts(t *testing.T) { 63 data := ints 64 Ints(data[0:]) 65 if !IntsAreSorted(data[0:]) { 66 t.Errorf("sorted %v", ints) 67 t.Errorf(" got %v", data) 68 } 69 } 70 71 func TestFloat64s(t *testing.T) { 72 data := float64s 73 Float64s(data[0:]) 74 if !Float64sAreSorted(data[0:]) { 75 t.Errorf("sorted %v", float64s) 76 t.Errorf(" got %v", data) 77 } 78 } 79 80 func TestStrings(t *testing.T) { 81 data := strings 82 Strings(data[0:]) 83 if !StringsAreSorted(data[0:]) { 84 t.Errorf("sorted %v", strings) 85 t.Errorf(" got %v", data) 86 } 87 } 88 89 func TestStringsWithSwapper(t *testing.T) { 90 data := strings 91 With(len(data), reflectutil.Swapper(data[:]), func(i, j int) bool { 92 return data[i] < data[j] 93 }) 94 if !StringsAreSorted(data[:]) { 95 t.Errorf("sorted %v", strings) 96 t.Errorf(" got %v", data) 97 } 98 } 99 100 func TestSortLarge_Random(t *testing.T) { 101 n := 1000000 102 if testing.Short() { 103 n /= 100 104 } 105 data := make([]int, n) 106 for i := 0; i < len(data); i++ { 107 data[i] = rand.Intn(100) 108 } 109 if IntsAreSorted(data) { 110 t.Fatalf("terrible rand.rand") 111 } 112 Ints(data) 113 if !IntsAreSorted(data) { 114 t.Errorf("sort didn't sort - 1M ints") 115 } 116 } 117 118 func TestReverseSortIntSlice(t *testing.T) { 119 data := ints 120 data1 := ints 121 a := IntSlice(data[0:]) 122 Sort(a) 123 r := IntSlice(data1[0:]) 124 Sort(Reverse(r)) 125 for i := 0; i < len(data); i++ { 126 if a[i] != r[len(data)-1-i] { 127 t.Errorf("reverse sort didn't sort") 128 } 129 if i > len(data)/2 { 130 break 131 } 132 } 133 } 134 135 type nonDeterministicTestingData struct { 136 r *rand.Rand 137 } 138 139 func (t *nonDeterministicTestingData) Len() int { 140 return 500 141 } 142 func (t *nonDeterministicTestingData) Less(i, j int) bool { 143 if i < 0 || j < 0 || i >= t.Len() || j >= t.Len() { 144 panic("nondeterministic comparison out of bounds") 145 } 146 return t.r.Float32() < 0.5 147 } 148 func (t *nonDeterministicTestingData) Swap(i, j int) { 149 if i < 0 || j < 0 || i >= t.Len() || j >= t.Len() { 150 panic("nondeterministic comparison out of bounds") 151 } 152 } 153 154 func TestNonDeterministicComparison(t *testing.T) { 155 // Ensure that sort.Sort does not panic when Less returns inconsistent results. 156 // See https://golang.org/issue/14377. 157 defer func() { 158 if r := recover(); r != nil { 159 t.Error(r) 160 } 161 }() 162 163 td := &nonDeterministicTestingData{ 164 r: rand.New(rand.NewSource(0)), 165 } 166 167 for i := 0; i < 10; i++ { 168 Sort(td) 169 } 170 } 171 172 func BenchmarkSortString1K(b *testing.B) { 173 b.StopTimer() 174 unsorted := make([]string, 1<<10) 175 for i := range unsorted { 176 unsorted[i] = strconv.Itoa(i ^ 0x2cc) 177 } 178 data := make([]string, len(unsorted)) 179 180 for i := 0; i < b.N; i++ { 181 copy(data, unsorted) 182 b.StartTimer() 183 Strings(data) 184 b.StopTimer() 185 } 186 } 187 188 func BenchmarkSortString1K_With(b *testing.B) { 189 b.StopTimer() 190 unsorted := make([]string, 1<<10) 191 for i := range unsorted { 192 unsorted[i] = strconv.Itoa(i ^ 0x2cc) 193 } 194 data := make([]string, len(unsorted)) 195 196 for i := 0; i < b.N; i++ { 197 copy(data, unsorted) 198 b.StartTimer() 199 With(len(data), 200 func(i, j int) { data[i], data[j] = data[j], data[i] }, 201 func(i, j int) bool { 202 return data[i] < data[j] 203 }) 204 b.StopTimer() 205 } 206 } 207 208 func BenchmarkSortString1K_WithSwapper(b *testing.B) { 209 b.StopTimer() 210 unsorted := make([]string, 1<<10) 211 for i := range unsorted { 212 unsorted[i] = strconv.Itoa(i ^ 0x2cc) 213 } 214 data := make([]string, len(unsorted)) 215 216 for i := 0; i < b.N; i++ { 217 copy(data, unsorted) 218 b.StartTimer() 219 With(len(data), reflectutil.Swapper(data), func(i, j int) bool { 220 return data[i] < data[j] 221 }) 222 b.StopTimer() 223 } 224 } 225 226 func BenchmarkStableString1K(b *testing.B) { 227 b.StopTimer() 228 unsorted := make([]string, 1<<10) 229 for i := 0; i < len(data); i++ { 230 unsorted[i] = strconv.Itoa(i ^ 0x2cc) 231 } 232 data := make([]string, len(unsorted)) 233 234 for i := 0; i < b.N; i++ { 235 copy(data, unsorted) 236 b.StartTimer() 237 Stable(StringSlice(data)) 238 b.StopTimer() 239 } 240 } 241 242 func BenchmarkSortInt1K(b *testing.B) { 243 b.StopTimer() 244 for i := 0; i < b.N; i++ { 245 data := make([]int, 1<<10) 246 for i := 0; i < len(data); i++ { 247 data[i] = i ^ 0x2cc 248 } 249 b.StartTimer() 250 Ints(data) 251 b.StopTimer() 252 } 253 } 254 255 func BenchmarkStableInt1K(b *testing.B) { 256 b.StopTimer() 257 unsorted := make([]int, 1<<10) 258 for i := range unsorted { 259 unsorted[i] = i ^ 0x2cc 260 } 261 data := make([]int, len(unsorted)) 262 for i := 0; i < b.N; i++ { 263 copy(data, unsorted) 264 b.StartTimer() 265 Stable(IntSlice(data)) 266 b.StopTimer() 267 } 268 } 269 270 func BenchmarkStableInt1K_With(b *testing.B) { 271 b.StopTimer() 272 unsorted := make([]int, 1<<10) 273 for i := range unsorted { 274 unsorted[i] = i ^ 0x2cc 275 } 276 data := make([]int, len(unsorted)) 277 for i := 0; i < b.N; i++ { 278 copy(data, unsorted) 279 b.StartTimer() 280 Stable(MakeInterface( 281 len(data), 282 func(i, j int) { data[i], data[j] = data[j], data[i] }, 283 func(i, j int) bool { return data[i] < data[j] }, 284 )) 285 b.StopTimer() 286 } 287 } 288 289 func BenchmarkStableInt1K_WithSwapper(b *testing.B) { 290 b.StopTimer() 291 unsorted := make([]int, 1<<10) 292 for i := range unsorted { 293 unsorted[i] = i ^ 0x2cc 294 } 295 data := make([]int, len(unsorted)) 296 for i := 0; i < b.N; i++ { 297 copy(data, unsorted) 298 b.StartTimer() 299 Stable(MakeInterface(len(data), reflectutil.Swapper(data), func(i, j int) bool { 300 return data[i] < data[j] 301 })) 302 b.StopTimer() 303 } 304 } 305 306 func BenchmarkSortInt64K(b *testing.B) { 307 b.StopTimer() 308 for i := 0; i < b.N; i++ { 309 data := make([]int, 1<<16) 310 for i := 0; i < len(data); i++ { 311 data[i] = i ^ 0xcccc 312 } 313 b.StartTimer() 314 Ints(data) 315 b.StopTimer() 316 } 317 } 318 319 func BenchmarkStableInt64K(b *testing.B) { 320 b.StopTimer() 321 for i := 0; i < b.N; i++ { 322 data := make([]int, 1<<16) 323 for i := 0; i < len(data); i++ { 324 data[i] = i ^ 0xcccc 325 } 326 b.StartTimer() 327 Stable(IntSlice(data)) 328 b.StopTimer() 329 } 330 } 331 332 const ( 333 _Sawtooth = iota 334 _Rand 335 _Stagger 336 _Plateau 337 _Shuffle 338 _NDist 339 ) 340 341 const ( 342 _Copy = iota 343 _Reverse 344 _ReverseFirstHalf 345 _ReverseSecondHalf 346 _Sorted 347 _Dither 348 _NMode 349 ) 350 351 type testingData struct { 352 desc string 353 t *testing.T 354 data []int 355 maxswap int // number of swaps allowed 356 ncmp, nswap int 357 } 358 359 func (d *testingData) Len() int { return len(d.data) } 360 func (d *testingData) Less(i, j int) bool { 361 d.ncmp++ 362 return d.data[i] < d.data[j] 363 } 364 func (d *testingData) Swap(i, j int) { 365 if d.nswap >= d.maxswap { 366 d.t.Errorf("%s: used %d swaps sorting slice of %d", d.desc, d.nswap, len(d.data)) 367 d.t.FailNow() 368 } 369 d.nswap++ 370 d.data[i], d.data[j] = d.data[j], d.data[i] 371 } 372 373 func min(a, b int) int { 374 if a < b { 375 return a 376 } 377 return b 378 } 379 380 func lg(n int) int { 381 i := 0 382 for 1<<uint(i) < n { 383 i++ 384 } 385 return i 386 } 387 388 func testBentleyMcIlroy(t *testing.T, sort func(Interface), maxswap func(int) int) { 389 sizes := []int{100, 1023, 1024, 1025} 390 if testing.Short() { 391 sizes = []int{100, 127, 128, 129} 392 } 393 dists := []string{"sawtooth", "rand", "stagger", "plateau", "shuffle"} 394 modes := []string{"copy", "reverse", "reverse1", "reverse2", "sort", "dither"} 395 var tmp1, tmp2 [1025]int 396 for _, n := range sizes { 397 for m := 1; m < 2*n; m *= 2 { 398 for dist := 0; dist < _NDist; dist++ { 399 j := 0 400 k := 1 401 data := tmp1[0:n] 402 for i := 0; i < n; i++ { 403 switch dist { 404 case _Sawtooth: 405 data[i] = i % m 406 case _Rand: 407 data[i] = rand.Intn(m) 408 case _Stagger: 409 data[i] = (i*m + i) % n 410 case _Plateau: 411 data[i] = min(i, m) 412 case _Shuffle: 413 if rand.Intn(m) != 0 { 414 j += 2 415 data[i] = j 416 } else { 417 k += 2 418 data[i] = k 419 } 420 } 421 } 422 423 mdata := tmp2[0:n] 424 for mode := 0; mode < _NMode; mode++ { 425 switch mode { 426 case _Copy: 427 for i := 0; i < n; i++ { 428 mdata[i] = data[i] 429 } 430 case _Reverse: 431 for i := 0; i < n; i++ { 432 mdata[i] = data[n-i-1] 433 } 434 case _ReverseFirstHalf: 435 for i := 0; i < n/2; i++ { 436 mdata[i] = data[n/2-i-1] 437 } 438 for i := n / 2; i < n; i++ { 439 mdata[i] = data[i] 440 } 441 case _ReverseSecondHalf: 442 for i := 0; i < n/2; i++ { 443 mdata[i] = data[i] 444 } 445 for i := n / 2; i < n; i++ { 446 mdata[i] = data[n-(i-n/2)-1] 447 } 448 case _Sorted: 449 for i := 0; i < n; i++ { 450 mdata[i] = data[i] 451 } 452 // Ints is known to be correct 453 // because mode Sort runs after mode _Copy. 454 Ints(mdata) 455 case _Dither: 456 for i := 0; i < n; i++ { 457 mdata[i] = data[i] + i%5 458 } 459 } 460 461 desc := fmt.Sprintf("n=%d m=%d dist=%s mode=%s", n, m, dists[dist], modes[mode]) 462 d := &testingData{desc: desc, t: t, data: mdata[0:n], maxswap: maxswap(n)} 463 sort(d) 464 // Uncomment if you are trying to improve the number of compares/swaps. 465 //t.Logf("%s: ncmp=%d, nswp=%d", desc, d.ncmp, d.nswap) 466 467 // If we were testing C qsort, we'd have to make a copy 468 // of the slice and sort it ourselves and then compare 469 // x against it, to ensure that qsort was only permuting 470 // the data, not (for example) overwriting it with zeros. 471 // 472 // In go, we don't have to be so paranoid: since the only 473 // mutating method Sort can call is TestingData.swap, 474 // it suffices here just to check that the final slice is sorted. 475 if !IntsAreSorted(mdata) { 476 t.Errorf("%s: ints not sorted", desc) 477 t.Errorf("\t%v", mdata) 478 t.FailNow() 479 } 480 } 481 } 482 } 483 } 484 } 485 486 func TestSortBM(t *testing.T) { 487 testBentleyMcIlroy(t, Sort, func(n int) int { return n * lg(n) * 12 / 10 }) 488 } 489 490 func TestHeapsortBM(t *testing.T) { 491 testBentleyMcIlroy(t, Heapsort, func(n int) int { return n * lg(n) * 12 / 10 }) 492 } 493 494 func TestStableBM(t *testing.T) { 495 testBentleyMcIlroy(t, Stable, func(n int) int { return n * lg(n) * lg(n) / 3 }) 496 } 497 498 // This is based on the "antiquicksort" implementation by M. Douglas McIlroy. 499 // See http://www.cs.dartmouth.edu/~doug/mdmspe.pdf for more info. 500 type adversaryTestingData struct { 501 data []int 502 keys map[int]int 503 candidate int 504 } 505 506 func (d *adversaryTestingData) Len() int { return len(d.data) } 507 508 func (d *adversaryTestingData) Less(i, j int) bool { 509 if _, present := d.keys[i]; !present { 510 if _, present := d.keys[j]; !present { 511 if i == d.candidate { 512 d.keys[i] = len(d.keys) 513 } else { 514 d.keys[j] = len(d.keys) 515 } 516 } 517 } 518 519 if _, present := d.keys[i]; !present { 520 d.candidate = i 521 return false 522 } 523 if _, present := d.keys[j]; !present { 524 d.candidate = j 525 return true 526 } 527 528 return d.keys[i] >= d.keys[j] 529 } 530 531 func (d *adversaryTestingData) Swap(i, j int) { 532 d.data[i], d.data[j] = d.data[j], d.data[i] 533 } 534 535 func TestAdversary(t *testing.T) { 536 const size = 100 537 data := make([]int, size) 538 for i := 0; i < size; i++ { 539 data[i] = i 540 } 541 542 d := &adversaryTestingData{data, make(map[int]int), 0} 543 Sort(d) // This should degenerate to heapsort. 544 } 545 546 func TestStableInts(t *testing.T) { 547 data := ints 548 Stable(IntSlice(data[0:])) 549 if !IntsAreSorted(data[0:]) { 550 t.Errorf("nsorted %v\n got %v", ints, data) 551 } 552 } 553 554 type intPairs []struct { 555 a, b int 556 } 557 558 // IntPairs compare on a only. 559 func (d intPairs) Len() int { return len(d) } 560 func (d intPairs) Less(i, j int) bool { return d[i].a < d[j].a } 561 func (d intPairs) Swap(i, j int) { d[i], d[j] = d[j], d[i] } 562 563 // Record initial order in B. 564 func (d intPairs) initB() { 565 for i := range d { 566 d[i].b = i 567 } 568 } 569 570 // InOrder checks if a-equal elements were not reordered. 571 func (d intPairs) inOrder() bool { 572 lastA, lastB := -1, 0 573 for i := 0; i < len(d); i++ { 574 if lastA != d[i].a { 575 lastA = d[i].a 576 lastB = d[i].b 577 continue 578 } 579 if d[i].b <= lastB { 580 return false 581 } 582 lastB = d[i].b 583 } 584 return true 585 } 586 587 func TestStability(t *testing.T) { 588 n, m := 100000, 1000 589 if testing.Short() { 590 n, m = 1000, 100 591 } 592 data := make(intPairs, n) 593 594 // random distribution 595 for i := 0; i < len(data); i++ { 596 data[i].a = rand.Intn(m) 597 } 598 if IsSorted(data) { 599 t.Fatalf("terrible rand.rand") 600 } 601 data.initB() 602 Stable(data) 603 if !IsSorted(data) { 604 t.Errorf("Stable didn't sort %d ints", n) 605 } 606 if !data.inOrder() { 607 t.Errorf("Stable wasn't stable on %d ints", n) 608 } 609 610 // already sorted 611 data.initB() 612 Stable(data) 613 if !IsSorted(data) { 614 t.Errorf("Stable shuffled sorted %d ints (order)", n) 615 } 616 if !data.inOrder() { 617 t.Errorf("Stable shuffled sorted %d ints (stability)", n) 618 } 619 620 // sorted reversed 621 for i := 0; i < len(data); i++ { 622 data[i].a = len(data) - i 623 } 624 data.initB() 625 Stable(data) 626 if !IsSorted(data) { 627 t.Errorf("Stable didn't sort %d ints", n) 628 } 629 if !data.inOrder() { 630 t.Errorf("Stable wasn't stable on %d ints", n) 631 } 632 } 633 634 var countOpsSizes = []int{1e2, 3e2, 1e3, 3e3, 1e4, 3e4, 1e5, 3e5, 1e6} 635 636 func countOps(t *testing.T, algo func(Interface), name string) { 637 sizes := countOpsSizes 638 if testing.Short() { 639 sizes = sizes[:5] 640 } 641 if !testing.Verbose() { 642 t.Skip("Counting skipped as non-verbose mode.") 643 } 644 for _, n := range sizes { 645 td := testingData{ 646 desc: name, 647 t: t, 648 data: make([]int, n), 649 maxswap: 1<<31 - 1, 650 } 651 for i := 0; i < n; i++ { 652 td.data[i] = rand.Intn(n / 5) 653 } 654 algo(&td) 655 t.Logf("%s %8d elements: %11d Swap, %10d Less", name, n, td.nswap, td.ncmp) 656 } 657 } 658 659 func TestCountStableOps(t *testing.T) { countOps(t, Stable, "Stable") } 660 func TestCountSortOps(t *testing.T) { countOps(t, Sort, "Sort ") } 661 662 func bench(b *testing.B, size int, algo func(Interface), name string) { 663 b.StopTimer() 664 data := make(intPairs, size) 665 x := ^uint32(0) 666 for i := 0; i < b.N; i++ { 667 for n := size - 3; n <= size+3; n++ { 668 for i := 0; i < len(data); i++ { 669 x += x 670 x ^= 1 671 if int32(x) < 0 { 672 x ^= 0x88888eef 673 } 674 data[i].a = int(x % uint32(n/5)) 675 } 676 data.initB() 677 b.StartTimer() 678 algo(data) 679 b.StopTimer() 680 if !IsSorted(data) { 681 b.Errorf("%s did not sort %d ints", name, n) 682 } 683 if name == "Stable" && !data.inOrder() { 684 b.Errorf("%s unstable on %d ints", name, n) 685 } 686 } 687 } 688 } 689 690 func BenchmarkSort1e2(b *testing.B) { bench(b, 1e2, Sort, "Sort") } 691 func BenchmarkStable1e2(b *testing.B) { bench(b, 1e2, Stable, "Stable") } 692 func BenchmarkSort1e4(b *testing.B) { bench(b, 1e4, Sort, "Sort") } 693 func BenchmarkStable1e4(b *testing.B) { bench(b, 1e4, Stable, "Stable") } 694 func BenchmarkSort1e6(b *testing.B) { bench(b, 1e6, Sort, "Sort") } 695 func BenchmarkStable1e6(b *testing.B) { bench(b, 1e6, Stable, "Stable") }