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