├── LICENSE_1_0.txt ├── Makefile ├── README.md ├── plots.gnuplot ├── plots ├── .done ├── gbooks_freq.svg ├── m3killer.svg ├── organpipe.svg ├── plot.svg ├── random.svg ├── random01.svg ├── rotated.svg └── sorted.svg ├── results ├── gbooks_freq ├── gbooks_freq.comps ├── gbooks_freq.rsd ├── gbooks_freq.swaps ├── m3killer ├── m3killer.comps ├── m3killer.max_comps ├── m3killer.rsd ├── m3killer.swaps ├── organpipe ├── organpipe.comps ├── organpipe.max_comps ├── organpipe.rsd ├── organpipe.swaps ├── random ├── random.comps ├── random.max_comps ├── random.rsd ├── random.swaps ├── random01 ├── random01.comps ├── random01.max_comps ├── random01.rsd ├── random01.swaps ├── rotated ├── rotated.comps ├── rotated.max_comps ├── rotated.rsd ├── rotated.swaps ├── sorted ├── sorted.comps ├── sorted.max_comps ├── sorted.rsd └── sorted.swaps ├── src ├── bfprt_baseline.cpp ├── common.h ├── instrumented_double.h ├── main.cpp ├── median_of_ninthers.cpp ├── median_of_ninthers.h ├── ninther.cpp ├── nth_element.cpp ├── nth_element_reference.cpp ├── rnd3pivot.cpp └── timer.h └── support ├── aggregate_ngrams.d ├── binarize.d └── generate.d /LICENSE_1_0.txt: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Definitions pertanining to the project 2 | 3 | # $D is a directory for data that is generated but should not be discarded 4 | # naively. $T is a temporary directory for object files, generated binaries, and 5 | # intermediate results. $R is the directory where the final summary results are 6 | # kept. 7 | D = $(HOME)/data/median 8 | R = results 9 | T = /tmp/MedianOfNinthers 10 | $(shell mkdir -p $D $R $T) 11 | 12 | # Data sizes present in the paper 13 | SIZES = 10000 31620 100000 316220 1000000 3162280 10000000 14 | 15 | # Compiler flags for instrumented and fast build 16 | CFLAGS_INSTRUMENTED = -std=c++14 -O3 -DCOUNT_SWAPS -DCOUNT_WASTED_SWAPS -DCOUNT_COMPARISONS 17 | CFLAGS = -std=c++14 -O3 -DNDEBUG -DMEASURE_TIME 18 | 19 | # Utils 20 | XPROD = $(foreach a,$1,$(foreach b,$3,$a$2$b)) 21 | XPROD3 = $(call XPROD,$1,$2,$(call XPROD,$3,$4,$5)) 22 | 23 | # Sources (without algos) 24 | CXX_CODE = $(addprefix src/,main.cpp common.h timer.h) 25 | 26 | # Algorithms 27 | ALGOS = nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 28 | 29 | # Data sets (synthetic) 30 | SYNTHETIC_DATASETS = m3killer organpipe random random01 rotated sorted 31 | # Benchmark files we're interested in 32 | MK_OUTFILES = MEASUREMENTS_$1 = $(foreach n,$(SIZES),$(foreach a,$(ALGOS),$T/$1_$n_$a.time)) 33 | $(foreach d,$(SYNTHETIC_DATASETS),$(eval $(call MK_OUTFILES,$d))) 34 | 35 | # Data sets (Google Books) 36 | L = a b c d e f g h i j k l m n o p q r s t u v w x y z 37 | GBOOKS_LANGS = eng fre ger ita rus spa 38 | GBOOKS_CORPORA = $(foreach l,$(GBOOKS_LANGS),googlebooks-$l-all-1gram-20120701) 39 | 40 | # All measurement output files 41 | MEASUREMENT_OUTPUTS = $(foreach x,$(SYNTHETIC_DATASETS),$(MEASUREMENTS_$x)) \ 42 | $(foreach x,$(call XPROD,$(ALGOS),_,$(GBOOKS_CORPORA)),$T/$x_freq.time) 43 | 44 | # Results files will be included in the paper. Change this to affect what 45 | # experiments are run. 46 | DATASETS = $(SYNTHETIC_DATASETS) gbooks_freq 47 | RESULTS = $(addprefix $R/,$(DATASETS)) 48 | PLOTS = $(addsuffix .svg,$(addprefix plots/,$(DATASETS))) 49 | 50 | ############################################################################### 51 | # Targets of interest 52 | ############################################################################### 53 | 54 | all: $(RESULTS) plots/.done 55 | 56 | clean: 57 | latexmk -C 58 | rm -rf $D/*.tmp $R*/* $T*/ $(PLOTS) plots/.done 59 | 60 | pristine: 61 | rm -rf $D/ $R/* $T/ $(PLOTS) plots/.done 62 | 63 | ################################################################################ 64 | # Data 65 | ################################################################################ 66 | 67 | .PHONY: data 68 | data: $(foreach x,$(call XPROD,$(SYNTHETIC_DATASETS),_,$(SIZES)),$D/$x.dat) $(foreach c,$(GBOOKS_CORPORA),$D/$c_freq.dat) 69 | 70 | $D/googlebooks-%_freq.dat: $D/googlebooks-%.txt 71 | cut -f 2 <$^ | rdmd -O -inline support/binarize.d >$@.tmp 72 | mv $@.tmp $@ 73 | $D/googlebooks-%.txt: $(foreach l,$L,$D/googlebooks-%-$l.gz) 74 | gunzip --stdout $^ | rdmd -O -inline support/aggregate_ngrams.d >$@.tmp 75 | mv $@.tmp $@ 76 | $D/googlebooks-%.gz: 77 | curl --fail http://storage.googleapis.com/books/ngrams/books/googlebooks-$*.gz >$@.tmp 78 | mv $@.tmp $@ 79 | 80 | define GENERATE_DATA 81 | $D/$1_%.dat: support/generate.d 82 | rdmd -O -inline support/generate.d --kind=$1 --n=$$* >$$@.tmp 83 | mv $$@.tmp $$@ 84 | endef 85 | 86 | $(foreach d,$(SYNTHETIC_DATASETS),$(eval $(call GENERATE_DATA,$d))) 87 | 88 | ################################################################################ 89 | # Measurements 90 | ################################################################################ 91 | 92 | .PHONY: measurements $(SYNTHETIC_DATASETS) $(GBOOKS_CORPORA) 93 | measurements: $(SYNTHETIC_DATASETS) $(GBOOKS_CORPORA) 94 | 95 | gbooks: $(foreach x,$(call XPROD,$(GBOOKS_CORPORA),_freq_,$(ALGOS)),$T/$x.time) 96 | 97 | $(foreach d,$(SYNTHETIC_DATASETS),$(eval \ 98 | $d: $(MEASUREMENTS_$d);\ 99 | )) 100 | 101 | define MAKE_MEASUREMENT 102 | $T/%_$1.time: $T/$1 $T/$1_instrumented $D/%.dat 103 | $T/$1 $D/$$*.dat >$T/$$*_$1.tmp 104 | $T/$1_instrumented $D/$$*.dat >>$T/$$*_$1.tmp 105 | mv $T/$$*_$1.tmp $T/$$*_$1.stats 106 | sed -n '/^milliseconds: /s/milliseconds: //p' $T/$$*_$1.stats >$T/$$*_$1.tmp 107 | mv $T/$$*_$1.tmp $$@ 108 | sed -n '/^rsd: /s/rsd: //p' $T/$$*_$1.stats >$T/$$*_$1.tmp 109 | mv $T/$$*_$1.tmp $T/$$*_$1.rsd 110 | sed -n '/^comparisons: /s/comparisons: //p' $T/$$*_$1.stats >$T/$$*_$1.tmp 111 | mv $T/$$*_$1.tmp $T/$$*_$1.comps 112 | sed -n '/^max_comparisons: /s/max_comparisons: //p' $T/$$*_$1.stats >$T/$$*_$1.tmp 113 | mv $T/$$*_$1.tmp $T/$$*_$1.max_comps 114 | sed -n '/^swaps: /s/swaps: //p' $T/$$*_$1.stats >$T/$$*_$1.tmp 115 | mv $T/$$*_$1.tmp $T/$$*_$1.swaps 116 | $T/$1: src/$1.cpp $(CXX_CODE) 117 | $(CXX) $(CFLAGS) -o $$@ $$(patsubst %.h,,$$^) 118 | $T/$1_instrumented: src/$1.cpp $(CXX_CODE) 119 | $(CXX) $(CFLAGS_INSTRUMENTED) -o $$@ $$(patsubst %.h,,$$^) 120 | endef 121 | 122 | $(foreach a,$(ALGOS),$(eval $(call MAKE_MEASUREMENT,$a))) 123 | 124 | ################################################################################ 125 | # Assemble measurement results 126 | ################################################################################ 127 | 128 | $R/gbooks_freq: gbooks 129 | echo "Corpus" $(foreach a,$(ALGOS), " $a") >$@.tmp 130 | $(foreach l,$(GBOOKS_LANGS),printf "$l " >>$@.tmp && paste $(foreach a,$(ALGOS),$T/googlebooks-$l-all-1gram-20120701_freq_$a.time) >>$@.tmp &&) true 131 | mv $@.tmp $@ 132 | echo "Corpus" $(foreach a,$(ALGOS), " $a") >$@.tmp 133 | $(foreach l,$(GBOOKS_LANGS),printf "$l " >>$@.tmp && paste $(foreach a,$(ALGOS),$T/googlebooks-$l-all-1gram-20120701_freq_$a.rsd) >>$@.tmp &&) true 134 | mv $@.tmp $@.rsd 135 | echo "Corpus" $(foreach a,$(ALGOS), " $a") >$@.tmp 136 | $(foreach l,$(GBOOKS_LANGS),printf "$l " >>$@.tmp && paste $(foreach a,$(ALGOS),$T/googlebooks-$l-all-1gram-20120701_freq_$a.comps) >>$@.tmp &&) true 137 | mv $@.tmp $@.comps 138 | echo "Corpus" $(foreach a,$(ALGOS), " $a") >$@.tmp 139 | $(foreach l,$(GBOOKS_LANGS),printf "$l " >>$@.tmp && paste $(foreach a,$(ALGOS),$T/googlebooks-$l-all-1gram-20120701_freq_$a.swaps) >>$@.tmp &&) true 140 | mv $@.tmp $@.swaps 141 | 142 | define MAKE_RESULT_FILE 143 | $R/$1: $$(MEASUREMENTS_$1) 144 | echo "Size" $$(foreach a,$$(ALGOS), " $$a") >$$@.tmp 145 | $$(foreach n,$$(SIZES),printf "$$n\t" >>$$@.tmp && paste $$(foreach a,$$(ALGOS),$$T/$1_$$n_$$a.time) >>$$@.tmp &&) true 146 | mv $$@.tmp $$@ 147 | # Relative Standard Deviation 148 | echo "Size" $$(foreach a,$$(ALGOS), " $$a") >$$@.tmp 149 | $$(foreach n,$$(SIZES),printf "$$n\t" >>$$@.tmp && paste $$(foreach a,$$(ALGOS),$$T/$1_$$n_$$a.rsd) >>$$@.tmp &&) true 150 | mv $$@.tmp $$@.rsd 151 | # Comparisons 152 | echo "Size" $$(foreach a,$$(ALGOS), " $$a") >$$@.tmp 153 | $$(foreach n,$$(SIZES),printf "$$n\t" >>$$@.tmp && paste $$(foreach a,$$(ALGOS),$$T/$1_$$n_$$a.comps) >>$$@.tmp &&) true 154 | mv $$@.tmp $$@.comps 155 | # Worst-case Comparisons 156 | echo "Size" $$(foreach a,$$(ALGOS), " $$a") >$$@.tmp 157 | $$(foreach n,$$(SIZES),printf "$$n\t" >>$$@.tmp && paste $$(foreach a,$$(ALGOS),$$T/$1_$$n_$$a.max_comps) >>$$@.tmp &&) true 158 | mv $$@.tmp $$@.max_comps 159 | # Swaps 160 | echo "Size" $$(foreach a,$$(ALGOS), " $$a") >$$@.tmp 161 | $$(foreach n,$$(SIZES),printf "$$n\t" >>$$@.tmp && paste $$(foreach a,$$(ALGOS),$$T/$1_$$n_$$a.swaps) >>$$@.tmp &&) true 162 | mv $$@.tmp $$@.swaps 163 | endef 164 | 165 | $(foreach a,$(SYNTHETIC_DATASETS),$(eval $(call MAKE_RESULT_FILE,$a))) 166 | 167 | ################################################################################ 168 | # Plots 169 | ################################################################################ 170 | 171 | plots/.done : $(RESULTS) 172 | gnuplot plots.gnuplot 173 | touch $@ 174 | 175 | # Supplemental dependencies 176 | median_of_ninthers.cpp: median_of_ninthers.h 177 | 178 | # Don't delete intermediary files 179 | .SECONDARY: 180 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This repository contains the implementation and benchmarks for the paper ["Fast Deterministic Selection"](https://erdani.com/research/sea2017.pdf). 2 | 3 | # Prerequisites 4 | 5 | You need the GNU C++ compiler (or the clang drop-in replacement). To prepare the datasets, you need the D compiler dmd, downloadable from http://dlang.org/download.html. 6 | 7 | # Running Benchmarks 8 | 9 | To initiate bulding and running benchmarks, simply run `make` from the repository directory. The first run will take a long time because it downloads and preprocesses the Google Ngrams corpus, The default directory of all corpora is `$(HOME)/data/median`. 10 | 11 | Binaries and intermediate files are produced by default in `/tmp/MedianOfNinthers`. The final (summarized) results are output in `./results`. You may change these locations by editing `Makefile`. 12 | -------------------------------------------------------------------------------- /plots.gnuplot: -------------------------------------------------------------------------------- 1 | set term svg mouse standalone size 800, 600 2 | set boxwidth 0.9 relative 3 | set style data histogram 4 | set style histogram clustered 5 | set style fill solid 1.0 border lt -1 6 | set xlabel "Input size" 7 | set ylabel "Speedup" 8 | set yrange [0:] 9 | set grid noxtics ytics 10 | set key outside 11 | set ytics 0.1 12 | 13 | xlabel(n) = gprintf("%.2t · 10^{%T}", n) 14 | 15 | do for [data in "m3killer organpipe random random01 rotated sorted"] { 16 | set title "Speedup relative to GNUIntroselect (" . data . " dataset)" 17 | input = "results/" . data 18 | set output "plots/" . data . ".svg" 19 | plot input using (column("nth_element")/column("nth_element")):xticlabels(xlabel($1)) title "GNUIntroselect", \ 20 | input using (column("nth_element")/column("rnd3pivot")):xticlabels(xlabel($1)) title "RND3Pivot", \ 21 | input using (column("nth_element")/column("ninther")):xticlabels(xlabel($1)) title "Ninther", \ 22 | input using (column("nth_element")/column("median_of_ninthers")):xticlabels(xlabel($1)) title "QuickselectAdaptive" 23 | } 24 | 25 | set title "Speedup relative to GNUIntroselect (googlebooks dataset)" 26 | input = "results/gbooks_freq" 27 | set output "plots/gbooks_freq.svg" 28 | plot input using (column("nth_element")/column("nth_element")):xticlabels(1) title "GNUIntroselect", \ 29 | input using (column("nth_element")/column("rnd3pivot")):xticlabels(1) title "RND3Pivot", \ 30 | input using (column("nth_element")/column("ninther")):xticlabels(1) title "Ninther", \ 31 | input using (column("nth_element")/column("median_of_ninthers")):xticlabels(1) title "QuickselectAdaptive" 32 | -------------------------------------------------------------------------------- /plots/.done: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andralex/MedianOfNinthers/9fa75b267e74d67b15dbd555311f1ea5f8568e1b/plots/.done -------------------------------------------------------------------------------- /plots/gbooks_freq.svg: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | Gnuplot 10 | Produced by GNUPLOT 5.2 patchlevel 2 11 | 12 | 391 | 392 | 393 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 0 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 0.1 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 0.2 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 0.3 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 0.4 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 0.5 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 0.6 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 0.7 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 0.8 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 0.9 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 1 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 1.1 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 1.2 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 1.3 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 1.4 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 1.5 634 | 635 | 636 | 637 | 638 | eng 639 | 640 | 641 | 642 | 643 | fre 644 | 645 | 646 | 647 | 648 | ger 649 | 650 | 651 | 652 | 653 | ita 654 | 655 | 656 | 657 | 658 | rus 659 | 660 | 661 | 662 | 663 | spa 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | Speedup 673 | 674 | 675 | 676 | 677 | Input size 678 | 679 | 680 | 681 | 682 | Speedup relative to GNUIntroselect (googlebooks dataset) 683 | 684 | 685 | GNUIntroselect 686 | 687 | 688 | 689 | GNUIntroselect 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | RND3Pivot 732 | 733 | 734 | 735 | RND3Pivot 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 | 755 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | 766 | 767 | 768 | 769 | 770 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | Ninther 778 | 779 | 780 | 781 | Ninther 782 | 783 | 784 | 785 | 786 | 787 | 788 | 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 804 | 805 | 806 | 807 | 808 | 809 | 810 | 811 | 812 | 813 | 814 | 815 | 816 | 817 | 818 | 819 | 820 | 821 | 822 | 823 | QuickselectAdaptive 824 | 825 | 826 | 827 | QuickselectAdaptive 828 | 829 | 830 | 831 | 832 | 833 | 834 | 835 | 836 | 837 | 838 | 839 | 840 | 841 | 842 | 843 | 844 | 845 | 846 | 847 | 848 | 849 | 850 | 851 | 852 | 853 | 854 | 855 | 856 | 857 | 858 | 859 | 860 | 861 | 862 | 863 | 864 | 865 | 866 | 867 | 868 | 869 | 870 | 871 | 872 | 873 | 874 | 875 | 876 | 877 | 878 | 879 | 880 | 903 | 904 | 905 | 908 | 909 | 912 | 913 | 916 | 917 | 920 | 921 | 923 | 924 | 925 | -------------------------------------------------------------------------------- /plots/m3killer.svg: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | Gnuplot 10 | Produced by GNUPLOT 5.2 patchlevel 2 11 | 12 | 391 | 392 | 393 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 0 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 0.1 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 0.2 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 0.3 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 0.4 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 0.5 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 0.6 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 0.7 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 0.8 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 0.9 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 1 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 1.1 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 1.2 595 | 596 | 597 | 598 | 599 | 1.00 · 104 600 | 601 | 602 | 603 | 604 | 3.16 · 104 605 | 606 | 607 | 608 | 609 | 1.00 · 105 610 | 611 | 612 | 613 | 614 | 3.16 · 105 615 | 616 | 617 | 618 | 619 | 1.00 · 106 620 | 621 | 622 | 623 | 624 | 3.16 · 106 625 | 626 | 627 | 628 | 629 | 1.00 · 107 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | Speedup 639 | 640 | 641 | 642 | 643 | Input size 644 | 645 | 646 | 647 | 648 | Speedup relative to GNUIntroselect (m3killer dataset) 649 | 650 | 651 | GNUIntroselect 652 | 653 | 654 | 655 | GNUIntroselect 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | RND3Pivot 703 | 704 | 705 | 706 | RND3Pivot 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | Ninther 754 | 755 | 756 | 757 | Ninther 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | 766 | 767 | 768 | 769 | 770 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | 784 | 785 | 786 | 787 | 788 | 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 804 | QuickselectAdaptive 805 | 806 | 807 | 808 | QuickselectAdaptive 809 | 810 | 811 | 812 | 813 | 814 | 815 | 816 | 817 | 818 | 819 | 820 | 821 | 822 | 823 | 824 | 825 | 826 | 827 | 828 | 829 | 830 | 831 | 832 | 833 | 834 | 835 | 836 | 837 | 838 | 839 | 840 | 841 | 842 | 843 | 844 | 845 | 846 | 847 | 848 | 849 | 850 | 851 | 852 | 853 | 854 | 855 | 856 | 857 | 858 | 859 | 860 | 861 | 862 | 863 | 864 | 865 | 866 | 889 | 890 | 891 | 894 | 895 | 898 | 899 | 902 | 903 | 906 | 907 | 909 | 910 | 911 | -------------------------------------------------------------------------------- /plots/random01.svg: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | Gnuplot 10 | Produced by GNUPLOT 5.2 patchlevel 2 11 | 12 | 391 | 392 | 393 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 0 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 0.1 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 0.2 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 0.3 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 0.4 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 0.5 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 0.6 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 0.7 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 0.8 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 0.9 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 1 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 1.1 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 1.2 595 | 596 | 597 | 598 | 599 | 1.00 · 104 600 | 601 | 602 | 603 | 604 | 3.16 · 104 605 | 606 | 607 | 608 | 609 | 1.00 · 105 610 | 611 | 612 | 613 | 614 | 3.16 · 105 615 | 616 | 617 | 618 | 619 | 1.00 · 106 620 | 621 | 622 | 623 | 624 | 3.16 · 106 625 | 626 | 627 | 628 | 629 | 1.00 · 107 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | Speedup 639 | 640 | 641 | 642 | 643 | Input size 644 | 645 | 646 | 647 | 648 | Speedup relative to GNUIntroselect (random01 dataset) 649 | 650 | 651 | GNUIntroselect 652 | 653 | 654 | 655 | GNUIntroselect 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | RND3Pivot 703 | 704 | 705 | 706 | RND3Pivot 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | Ninther 754 | 755 | 756 | 757 | Ninther 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | 766 | 767 | 768 | 769 | 770 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | 784 | 785 | 786 | 787 | 788 | 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 804 | QuickselectAdaptive 805 | 806 | 807 | 808 | QuickselectAdaptive 809 | 810 | 811 | 812 | 813 | 814 | 815 | 816 | 817 | 818 | 819 | 820 | 821 | 822 | 823 | 824 | 825 | 826 | 827 | 828 | 829 | 830 | 831 | 832 | 833 | 834 | 835 | 836 | 837 | 838 | 839 | 840 | 841 | 842 | 843 | 844 | 845 | 846 | 847 | 848 | 849 | 850 | 851 | 852 | 853 | 854 | 855 | 856 | 857 | 858 | 859 | 860 | 861 | 862 | 863 | 864 | 865 | 866 | 889 | 890 | 891 | 894 | 895 | 898 | 899 | 902 | 903 | 906 | 907 | 909 | 910 | 911 | -------------------------------------------------------------------------------- /results/gbooks_freq: -------------------------------------------------------------------------------- 1 | Corpus nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | eng 117.813 94.3962 162.796 135.193 396.285 3 | fre 49.6884 43.2072 70.1164 70.1366 169.702 4 | ger 77.9788 54.8565 92.1645 100.674 222.228 5 | ita 37.9593 27.978 43.4923 33.1497 106.293 6 | rus 64.8337 56.4429 93.1499 93.1186 224.038 7 | spa 50.0063 39.0704 55.7444 54.5203 134.703 8 | -------------------------------------------------------------------------------- /results/gbooks_freq.comps: -------------------------------------------------------------------------------- 1 | Corpus nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | eng 2.02023 2.01368 2.18472 1.95447 7.29315 3 | fre 2.57805 2.031 3.13799 2.28996 7.44904 4 | ger 2.38017 2.03388 3.03868 2.61722 7.53545 5 | ita 2.19042 2.05765 2.18802 1.95419 7.57667 6 | rus 1.98374 2.03477 3.56788 2.13806 7.43694 7 | spa 2.1926 2.08892 2.2668 2.09468 7.38337 8 | -------------------------------------------------------------------------------- /results/gbooks_freq.rsd: -------------------------------------------------------------------------------- 1 | Corpus nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | eng 0.00457156 0.00543685 0.129571 0.0247221 0.0242972 3 | fre 0.00476557 0.0156726 0.118464 0.00451085 0.00487697 4 | ger 0.00562102 0.00637091 0.113532 0.00658467 0.00535848 5 | ita 0.00598068 0.00791397 0.126841 0.00535468 0.00535212 6 | rus 0.00449159 0.00460021 0.115736 0.00460794 0.00421864 7 | spa 0.00480117 0.0065601 0.124025 0.00465915 0.00449202 8 | -------------------------------------------------------------------------------- /results/gbooks_freq.swaps: -------------------------------------------------------------------------------- 1 | Corpus nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | eng 0.451191 0.252984 0.537967 0.450908 3.43385 3 | fre 0.483192 0.267631 0.553471 0.549875 3.5031 4 | ger 0.530952 0.257616 0.648872 0.602313 3.48959 5 | ita 0.52195 0.27591 0.475848 0.434848 3.54749 6 | rus 0.449897 0.265186 0.592245 0.53424 3.4982 7 | spa 0.537337 0.309803 0.537237 0.519552 3.44127 8 | -------------------------------------------------------------------------------- /results/m3killer: -------------------------------------------------------------------------------- 1 | Size nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | 10000 0.00858097 0.0161205 0.0187849 0.0200504 0.111591 3 | 31620 0.0278762 0.0489345 0.0582746 0.0543233 0.281784 4 | 100000 0.0864959 0.158022 0.179497 0.163724 1.0518 5 | 316220 0.248881 0.473205 0.532748 0.527734 2.4164 6 | 1000000 1.25232 1.73201 1.85456 1.90807 9.43251 7 | 3162280 5.42039 7.12598 7.28006 4.89131 33.1493 8 | 10000000 19.0578 19.516 27.2404 27.9941 109.985 9 | -------------------------------------------------------------------------------- /results/m3killer.comps: -------------------------------------------------------------------------------- 1 | Size nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | 10000 2.001 2.3812 3.0937 2.8589 7.2334 3 | 31620 2.00032 2.37226 3.14298 2.96866 6.73153 4 | 100000 2.0001 2.31551 2.96003 2.83656 7.60242 5 | 316220 2.00003 2.5148 2.95383 2.99744 6.93506 6 | 1000000 2.00001 2.5111 5.09133 2.83433 7.67326 7 | 3162280 2 2.50604 3.94582 1.80001 7.78699 8 | 10000000 2 2.01958 3.09213 2.83404 7.7502 9 | -------------------------------------------------------------------------------- /results/m3killer.max_comps: -------------------------------------------------------------------------------- 1 | Size nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | 10000 2.001 2.3812 3.0937 2.8589 7.2334 3 | 31620 2.00032 2.37226 3.14298 2.96866 6.73153 4 | 100000 2.0001 2.31551 2.96003 2.83656 7.60242 5 | 316220 2.00003 2.5148 2.95383 2.99744 6.93506 6 | 1000000 2.00001 2.5111 5.09133 2.83433 7.67326 7 | 3162280 2 2.50604 3.94582 1.80001 7.78699 8 | 10000000 2 2.01958 3.09213 2.83404 7.7502 9 | -------------------------------------------------------------------------------- /results/m3killer.rsd: -------------------------------------------------------------------------------- 1 | Size nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | 10000 0.134957 0.104188 0.206411 0.0511648 0.142841 3 | 31620 0.262639 0.0508439 0.224724 0.108405 0.0596018 4 | 100000 0.107368 0.101568 0.233842 0.103733 0.0430431 5 | 316220 0.0224785 0.0211817 0.219022 0.0295251 0.00577407 6 | 1000000 0.0436512 0.0172808 0.186331 0.0143903 0.0180113 7 | 3162280 0.0517219 0.0302072 0.18317 0.0117676 0.0300457 8 | 10000000 0.0218366 0.0205977 0.173585 0.0233922 0.0117546 9 | -------------------------------------------------------------------------------- /results/m3killer.swaps: -------------------------------------------------------------------------------- 1 | Size nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | 10000 0.2502 0.3458 0.6152 0.4516 3.2523 3 | 31620 0.250063 0.341493 0.540987 0.411448 3.07622 4 | 100000 0.25002 0.33648 0.58706 0.44736 3.42197 5 | 316220 0.250006 0.448653 0.587164 0.408744 3.18851 6 | 1000000 0.250002 0.446196 0.525279 0.447043 3.39751 7 | 3162280 0.250001 0.445979 0.432731 0.250002 3.57144 8 | 10000000 0.25 0.255726 0.541548 0.447006 3.47586 9 | -------------------------------------------------------------------------------- /results/organpipe: -------------------------------------------------------------------------------- 1 | Size nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | 10000 0.00518679 0.00409736 0.00883075 0.00289263 0.0224094 3 | 31620 0.0160057 0.0123639 0.027103 0.0101452 0.0623793 4 | 100000 0.0486396 0.0391985 0.0790202 0.0289573 0.286742 5 | 316220 0.14899 0.102629 0.243459 0.0960446 0.739839 6 | 1000000 0.471531 0.324085 0.742923 0.27113 2.60552 7 | 3162280 2.33289 1.27396 2.92005 1.15959 9.9974 8 | 10000000 8.36737 4.13401 9.61188 3.70869 37.2826 9 | -------------------------------------------------------------------------------- /results/organpipe.comps: -------------------------------------------------------------------------------- 1 | Size nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | 10000 2.5036 1.2018 3.3144 1.0026 6.179 3 | 31620 2.50127 1.20335 3.31657 1.00082 5.52739 4 | 100000 2.50052 1.20426 3.31532 1.00026 6.22998 5 | 316220 2.50015 1.01261 3.31518 1.00008 5.87896 6 | 1000000 2.50006 1.01275 3.31506 1.00003 6.30194 7 | 3162280 2.50002 1.01191 3.31514 1.00001 6.68181 8 | 10000000 2.50001 1.01191 3.31868 1 6.3507 9 | -------------------------------------------------------------------------------- /results/organpipe.max_comps: -------------------------------------------------------------------------------- 1 | Size nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | 10000 2.5036 1.2018 3.3144 1.0026 6.179 3 | 31620 2.50127 1.20335 3.31657 1.00082 5.52739 4 | 100000 2.50052 1.20426 3.31532 1.00026 6.22998 5 | 316220 2.50015 1.01261 3.31518 1.00008 5.87896 6 | 1000000 2.50006 1.01275 3.31506 1.00003 6.30194 7 | 3162280 2.50002 1.01191 3.31514 1.00001 6.68181 8 | 10000000 2.50001 1.01191 3.31868 1 6.3507 9 | -------------------------------------------------------------------------------- /results/organpipe.rsd: -------------------------------------------------------------------------------- 1 | Size nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | 10000 0.0260573 0.00161172 0.223087 0.027141 0.0889261 3 | 31620 0.00347532 0.024052 0.219561 0.113355 0.0395298 4 | 100000 0.0467533 0.104677 0.219616 0.0671471 0.041455 5 | 316220 0.0623617 0.0283419 0.200283 0.0503981 0.0536869 6 | 1000000 0.0263516 0.0275057 0.200534 0.0417299 0.0215271 7 | 3162280 0.0189947 0.0491533 0.198481 0.0287048 0.0310142 8 | 10000000 0.0235939 0.0265271 0.225431 0.0391198 0.0240235 9 | -------------------------------------------------------------------------------- /results/organpipe.swaps: -------------------------------------------------------------------------------- 1 | Size nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | 10000 0.0024 0.0008 0.0044 0.0004 2.141 3 | 31620 0.000885515 0.000253004 0.00177103 0.000126502 1.80348 4 | 100000 0.00032 0.0001 0.00064 4e-05 2.17794 5 | 316220 0.00010752 2.52988e-05 0.000259313 1.26494e-05 1.9946 6 | 1000000 3.8e-05 1e-05 8e-05 4e-06 2.22486 7 | 3162280 1.32816e-05 2.52982e-06 2.97254e-05 1.26491e-06 2.46104 8 | 10000000 4.4e-06 1e-06 1.12e-05 4e-07 2.22673 9 | -------------------------------------------------------------------------------- /results/random: -------------------------------------------------------------------------------- 1 | Size nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | 10000 0.0744633 0.0601273 0.0813791 0.0781392 0.192157 3 | 31620 0.222571 0.177082 0.248516 0.25026 0.614056 4 | 100000 0.719618 0.529 0.772346 0.760976 1.97042 5 | 316220 2.15402 1.60674 2.48384 2.46957 6.19136 6 | 1000000 6.98936 4.95673 7.89867 7.95574 19.7354 7 | 3162280 23.1086 15.7516 25.7251 25.5195 62.8602 8 | 10000000 71.6749 48.5689 80.7408 79.8404 198.408 9 | -------------------------------------------------------------------------------- /results/random.comps: -------------------------------------------------------------------------------- 1 | Size nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | 10000 2.7954 2.30708 2.76658 2.39681 6.74818 3 | 31620 2.80688 2.26105 2.70252 2.42741 6.90953 4 | 100000 2.88963 2.21808 2.72259 2.32443 7.13767 5 | 316220 2.71749 2.06928 2.77001 2.46768 7.21298 6 | 1000000 2.73834 2.04151 2.76815 2.47151 7.29563 7 | 3162280 2.88673 2.02714 2.77313 2.51668 7.32883 8 | 10000000 2.80251 2.02048 2.75472 2.43825 7.34187 9 | -------------------------------------------------------------------------------- /results/random.max_comps: -------------------------------------------------------------------------------- 1 | Size nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | 10000 5.6567 2.6444 5.4636 3.4958 7.091 3 | 31620 4.21056 2.40525 4.47122 3.46635 7.22982 4 | 100000 4.22522 2.33424 4.85339 3.12605 7.31947 5 | 316220 4.32007 2.30147 4.72109 3.54377 7.43757 6 | 1000000 4.46092 2.12137 4.83704 3.7784 7.44431 7 | 3162280 5.78789 2.08221 4.54884 3.70242 7.471 8 | 10000000 4.73983 2.04093 4.33485 3.65776 7.49956 9 | -------------------------------------------------------------------------------- /results/random.rsd: -------------------------------------------------------------------------------- 1 | Size nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | 10000 0.125297 0.106343 0.12579 0.129747 0.106755 3 | 31620 0.140019 0.0697499 0.111638 0.109927 0.0863264 4 | 100000 0.112458 0.0504663 0.13721 0.0980392 0.0256999 5 | 316220 0.132162 0.0772275 0.128897 0.109546 0.0512982 6 | 1000000 0.121938 0.0608932 0.140533 0.100063 0.015636 7 | 3162280 0.111793 0.0266239 0.119195 0.11317 0.0160538 8 | 10000000 0.132279 0.0186661 0.121333 0.112876 0.0157413 9 | -------------------------------------------------------------------------------- /results/random.swaps: -------------------------------------------------------------------------------- 1 | Size nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | 10000 0.550255 0.327614 0.554048 0.529884 3.2772 3 | 31620 0.550875 0.300538 0.545093 0.53858 3.34504 4 | 100000 0.569518 0.286254 0.542897 0.524516 3.4619 5 | 316220 0.539733 0.288869 0.552467 0.543306 3.50093 6 | 1000000 0.54189 0.271818 0.54576 0.545208 3.53975 7 | 3162280 0.567651 0.262274 0.558248 0.55211 3.54427 8 | 10000000 0.550179 0.257747 0.550371 0.543869 3.54681 9 | -------------------------------------------------------------------------------- /results/random01: -------------------------------------------------------------------------------- 1 | Size nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | 10000 0.0575925 0.053695 0.0639878 0.064631 0.142829 3 | 31620 0.17287 0.162906 0.197321 0.205514 0.440888 4 | 100000 0.547084 0.515732 0.61858 0.635683 1.35206 5 | 316220 1.70679 1.43593 1.96716 2.01609 4.19058 6 | 1000000 5.49728 5.11804 6.32683 6.47476 13.3105 7 | 3162280 17.9226 16.2571 20.1311 20.7026 43.5439 8 | 10000000 57.4716 50.6564 64.4811 65.9602 142.782 9 | -------------------------------------------------------------------------------- /results/random01.comps: -------------------------------------------------------------------------------- 1 | Size nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | 10000 2.75306 2.97201 2.74161 2.71338 9.75048 3 | 31620 2.74603 2.74853 2.72335 2.70896 10.1076 4 | 100000 2.73136 2.85335 2.72929 2.70466 10.2775 5 | 316220 2.74767 2.37534 2.71658 2.70199 10.4048 6 | 1000000 2.76116 2.55553 2.72204 2.70421 10.4626 7 | 3162280 2.74026 2.49366 2.73703 2.70407 10.5152 8 | 10000000 2.76355 2.42263 2.72733 2.70809 10.5232 9 | -------------------------------------------------------------------------------- /results/random01.max_comps: -------------------------------------------------------------------------------- 1 | Size nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | 10000 3.2235 3.567 2.8817 2.8942 9.9446 3 | 31620 3.26996 3.46784 2.88624 2.86312 10.2157 4 | 100000 2.985 3.46079 2.88256 2.85407 10.3932 5 | 316220 2.96718 3.03067 2.88359 2.84786 10.5091 6 | 1000000 3.21648 3.03093 2.88151 2.85187 10.5838 7 | 3162280 3.21456 3.02939 2.98299 2.85099 10.6254 8 | 10000000 3.32846 3.02781 2.9829 2.84628 10.6499 9 | -------------------------------------------------------------------------------- /results/random01.rsd: -------------------------------------------------------------------------------- 1 | Size nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | 10000 0.046534 0.10545 0.0669739 0.0283408 0.0648692 3 | 31620 0.0500447 0.10777 0.0376455 0.0341108 0.0289966 4 | 100000 0.0405839 0.0971195 0.0393276 0.0258694 0.0155957 5 | 316220 0.0421543 0.066931 0.0356055 0.0267332 0.0140662 6 | 1000000 0.052202 0.105467 0.0310807 0.0224796 0.0125655 7 | 3162280 0.0319659 0.0768927 0.0332682 0.0199616 0.0130261 8 | 10000000 0.0210483 0.0756416 0.0214473 0.019275 0.0111106 9 | -------------------------------------------------------------------------------- /results/random01.swaps: -------------------------------------------------------------------------------- 1 | Size nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | 10000 0.99995 0.270627 0.999359 1.00036 3.47198 3 | 31620 0.999968 0.264268 0.999872 1.00028 3.5619 4 | 100000 0.99915 0.26336 0.99999 1.00011 3.61178 5 | 316220 1 0.250807 1.00003 0.999862 3.63045 6 | 1000000 0.999992 0.250955 1.00001 1.00001 3.6582 7 | 3162280 1 0.250773 1 1.00001 3.67114 8 | 10000000 1 0.250683 1 0.99998 3.66502 9 | -------------------------------------------------------------------------------- /results/rotated: -------------------------------------------------------------------------------- 1 | Size nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | 10000 0.0944806 0.0116615 0.0172713 0.0107525 0.0529267 3 | 31620 0.315224 0.0348388 0.0518263 0.0333019 0.149213 4 | 100000 1.12481 0.107144 0.155908 0.102438 0.587988 5 | 316220 3.92167 0.31186 0.471631 0.321495 1.56744 6 | 1000000 16.9122 1.15158 1.70474 1.27462 5.9 7 | 3162280 98.911 3.64135 5.75325 3.92595 20.2904 8 | 10000000 366.409 11.7121 18.8893 12.3791 82.0939 9 | -------------------------------------------------------------------------------- /results/rotated.comps: -------------------------------------------------------------------------------- 1 | Size nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | 10000 27.1516 1.70283 3.31667 1.50125 6.26957 3 | 31620 29.2138 1.70418 3.31681 1.5004 5.71234 4 | 100000 33.235 1.69054 3.31463 1.50012 6.47477 5 | 316220 37.244 1.51271 3.31486 1.50004 6.09781 6 | 1000000 39.2479 1.51276 3.31532 1.50001 6.54633 7 | 3162280 43.2492 1.51192 3.31514 1.5 5.98908 8 | 10000000 47.2497 1.51191 3.31864 1.5 6.5823 9 | -------------------------------------------------------------------------------- /results/rotated.max_comps: -------------------------------------------------------------------------------- 1 | Size nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | 10000 27.1516 1.70283 3.31667 1.50125 6.26957 3 | 31620 29.2138 1.70418 3.31681 1.5004 5.71234 4 | 100000 33.235 1.69054 3.31463 1.50012 6.47477 5 | 316220 37.244 1.51271 3.31486 1.50004 6.09781 6 | 1000000 39.2479 1.51276 3.31532 1.50001 6.54633 7 | 3162280 43.2492 1.51192 3.31514 1.5 5.98908 8 | 10000000 47.2497 1.51191 3.31864 1.5 6.5823 9 | -------------------------------------------------------------------------------- /results/rotated.rsd: -------------------------------------------------------------------------------- 1 | Size nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | 10000 0.0377674 0.0402735 0.230788 0.106823 0.0792906 3 | 31620 0.0326602 0.0631192 0.225742 0.0570579 0.0576544 4 | 100000 0.0132905 0.0500467 0.258086 0.0289721 0.0181346 5 | 316220 0.0105863 0.029395 0.225428 0.0303987 0.0178659 6 | 1000000 0.0686864 0.0277156 0.183019 0.0347488 0.0131135 7 | 3162280 0.0240797 0.0261649 0.201305 0.0428449 0.0183971 8 | 10000000 0.0161341 0.0292904 0.205179 0.0271785 0.0162955 9 | -------------------------------------------------------------------------------- /results/rotated.swaps: -------------------------------------------------------------------------------- 1 | Size nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | 10000 0.00529947 0.00059994 0.00449955 0.00039996 2.19318 3 | 31620 0.0018026 0.000221372 0.00170773 0.000126498 2.01733 4 | 100000 0.000649994 5.99994e-05 0.000489995 3.99996e-05 2.30494 5 | 316220 0.000230851 1.89741e-05 0.000183416 1.26494e-05 2.20789 6 | 1000000 7.69999e-05 6.99999e-06 5.99999e-05 4e-06 2.32079 7 | 3162280 2.68793e-05 2.21359e-06 2.43495e-05 1.26491e-06 2.01211 8 | 10000000 9.3e-06 7e-07 8.6e-06 4e-07 2.35244 9 | -------------------------------------------------------------------------------- /results/sorted: -------------------------------------------------------------------------------- 1 | Size nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | 10000 0.00991682 0.00771125 0.0173701 0.00569748 0.0553767 3 | 31620 0.0312159 0.0232467 0.0481715 0.0172812 0.14243 4 | 100000 0.0950594 0.0722384 0.151356 0.0540983 0.789689 5 | 316220 0.297247 0.202431 0.472186 0.169374 1.60031 6 | 1000000 1.39764 0.875969 1.80751 0.73581 5.83824 7 | 3162280 4.92823 2.50552 5.94299 2.50004 20.277 8 | 10000000 17.104 7.77382 19.6747 7.65679 81.6003 9 | -------------------------------------------------------------------------------- /results/sorted.comps: -------------------------------------------------------------------------------- 1 | Size nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | 10000 2.502 1.2029 3.3146 1.0013 6.3408 3 | 31620 2.5007 1.20421 3.31556 1.00041 5.63786 4 | 100000 2.50028 1.19055 3.31528 1.00013 6.47248 5 | 316220 2.50008 1.01271 3.31504 1.00004 6.07512 6 | 1000000 2.50003 1.01276 3.31544 1.00001 6.54869 7 | 3162280 2.50001 1.01192 3.31516 1 5.97787 8 | 10000000 2.5 1.01191 3.31858 1 6.57698 9 | -------------------------------------------------------------------------------- /results/sorted.max_comps: -------------------------------------------------------------------------------- 1 | Size nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | 10000 2.502 1.2029 3.3146 1.0013 6.3408 3 | 31620 2.5007 1.20421 3.31556 1.00041 5.63786 4 | 100000 2.50028 1.19055 3.31528 1.00013 6.47248 5 | 316220 2.50008 1.01271 3.31504 1.00004 6.07512 6 | 1000000 2.50003 1.01276 3.31544 1.00001 6.54869 7 | 3162280 2.50001 1.01192 3.31516 1 5.97787 8 | 10000000 2.5 1.01191 3.31858 1 6.57698 9 | -------------------------------------------------------------------------------- /results/sorted.rsd: -------------------------------------------------------------------------------- 1 | Size nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | 10000 0.0347544 0.0205802 0.223643 0.0536861 0.0758209 3 | 31620 0.0335265 0.0403367 0.201573 0.0241301 0.0250886 4 | 100000 0.032431 0.012113 0.213826 0.0398935 0.153203 5 | 316220 0.045292 0.0384148 0.217565 0.04733 0.0423037 6 | 1000000 0.0222171 0.0258816 0.188323 0.0298593 0.0282589 7 | 3162280 0.022853 0.0504264 0.211683 0.0279252 0.0214452 8 | 10000000 0.0416055 0.0408904 0.210291 0.0306775 0.015699 9 | -------------------------------------------------------------------------------- /results/sorted.swaps: -------------------------------------------------------------------------------- 1 | Size nth_element median_of_ninthers rnd3pivot ninther bfprt_baseline 2 | 10000 0.0013 0.0004 0.0023 0.0002 2.2369 3 | 31620 0.000474383 0.000158128 0.000980392 6.32511e-05 1.96689 4 | 100000 0.00017 4e-05 0.00038 2e-05 2.29844 5 | 316220 5.69224e-05 1.26494e-05 0.000139144 6.32471e-06 2.1839 6 | 1000000 2e-05 5e-06 4.7e-05 2e-06 2.31864 7 | 3162280 6.95701e-06 1.58114e-06 1.77087e-05 6.32455e-07 2.00662 8 | 10000000 2.3e-06 5e-07 4e-06 2e-07 2.33882 9 | -------------------------------------------------------------------------------- /src/bfprt_baseline.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright Andrei Alexandrescu, 2016-. 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://boost.org/LICENSE_1_0.txt) 5 | */ 6 | 7 | #include "common.h" 8 | #include 9 | 10 | template 11 | static T* partition(T* r, T* end) 12 | { 13 | const size_t len = end - r; 14 | if (len < 5) return pivotPartition(r, len / 2, len); 15 | size_t j = 0; 16 | for (size_t i = 4; i < len; i += 5, ++j) 17 | { 18 | partition5(r, i - 4, i - 3, i, i - 2, i - 1); 19 | cswap(r[i], r[j]); 20 | } 21 | quickselect(r, r + j / 2, r + j); 22 | return pivotPartition(r, j / 2, len); 23 | } 24 | 25 | void (*computeSelection)(double*, double*, double*) 26 | = &quickselect>; 27 | -------------------------------------------------------------------------------- /src/common.h: -------------------------------------------------------------------------------- 1 | /* Copyright Andrei Alexandrescu, 2016-. 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://boost.org/LICENSE_1_0.txt) 5 | */ 6 | 7 | #pragma once 8 | #include 9 | #include 10 | 11 | /** 12 | Instrumentation counters 13 | */ 14 | #ifdef COUNT_SWAPS 15 | extern unsigned long g_swaps; 16 | #endif 17 | #ifdef COUNT_WASTED_SWAPS 18 | extern unsigned long g_wastedSwaps; 19 | #endif 20 | #ifdef COUNT_COMPARISONS 21 | extern unsigned long g_comparisons; 22 | #endif 23 | 24 | /** 25 | Instrumented swap 26 | */ 27 | template 28 | inline void cswap(T& lhs, T& rhs) 29 | { 30 | std::swap(lhs, rhs); 31 | #ifdef COUNT_SWAPS 32 | ++g_swaps; 33 | #endif 34 | #ifdef COUNT_WASTED_SWAPS 35 | if (lhs == rhs) ++g_wastedSwaps; 36 | #endif 37 | } 38 | 39 | /** 40 | Instrumented comparisons 41 | */ 42 | #ifdef COUNT_COMPARISONS 43 | #define CNT (++g_comparisons, 0)+ 44 | #else 45 | #define CNT 46 | #endif 47 | 48 | /** 49 | Swaps the median of r[a], r[b], and r[c] into r[b]. 50 | */ 51 | template 52 | void median3(T* r, size_t a, size_t b, size_t c) 53 | { 54 | if (r[b] = r[b] && r[b] >= r[c]); 72 | } 73 | 74 | /** 75 | Sorts in place r[a], r[b], and r[c]. 76 | */ 77 | template 78 | void sort3(T* r, size_t a, size_t b, size_t c) 79 | { 80 | if (r[b] 125 | void partition4(T* r, size_t a, size_t b, size_t c, size_t d) 126 | { 127 | assert(a != b && a != c && a != d && b != c && b != d 128 | && c != d); 129 | /* static */ if (leanRight) 130 | { 131 | // In the median of 5 algorithm, consider r[e] infinite 132 | if (r[c] a. c->b, d->c, e->d 151 | if (r[c] 176 | void partition5(T* r, size_t a, size_t b, size_t c, size_t d, size_t e) 177 | { 178 | assert(a != b && a != c && a != d && a != e && b != c && b != d && b != e 179 | && c != d && c != e && d != e); 180 | if (r[c] 210 | T* pivotPartition(T* r, size_t k, size_t length) 211 | { 212 | assert(k < length); 213 | cswap(*r, r[k]); 214 | size_t lo = 1, hi = length - 1; 215 | for (;; ++lo, --hi) 216 | { 217 | for (;; ++lo) 218 | { 219 | if (lo > hi) goto loop_done; 220 | if (r[lo] >=CNT *r) break; 221 | } 222 | // found the left bound: r[lo] >= r[0] 223 | assert(lo <= hi); 224 | for (; *r = hi) break; 228 | // found the right bound: r[hi] <= r[0], swap & make progress 229 | assert(r[lo] >= r[hi]); 230 | cswap(r[lo], r[hi]); 231 | } 232 | loop_done: 233 | --lo; 234 | cswap(r[lo], *r); 235 | return r + lo; 236 | } 237 | 238 | /** 239 | Implements the quickselect algorithm, parameterized with a partition function. 240 | */ 241 | template 242 | void quickselect(T* r, T* mid, T* end) 243 | { 244 | if (r == end || mid >= end) return; 245 | assert(r <= mid && mid < end); 246 | for (;;) switch (end - r) 247 | { 248 | case 1: 249 | return; 250 | case 2: 251 | if (*r >CNT r[1]) cswap(*r, r[1]); 252 | return; 253 | case 3: 254 | sort3(r, 0, 1, 2); 255 | return; 256 | case 4: 257 | switch (mid - r) 258 | { 259 | case 0: goto select_min; 260 | case 1: partition4(r, 0, 1, 2, 3); break; 261 | case 2: partition4(r, 0, 1, 2, 3); break; 262 | case 3: goto select_max; 263 | default: assert(false); 264 | } 265 | return; 266 | default: 267 | assert(end - r > 4); 268 | if (r == mid) 269 | { 270 | select_min: 271 | auto pivot = r; 272 | for (++mid; mid < end; ++mid) 273 | if (*mid mid) 289 | { 290 | end = pivot; 291 | } 292 | else 293 | { 294 | r = pivot + 1; 295 | } 296 | } 297 | } 298 | 299 | /** 300 | Returns the index of the median of r[a], r[b], and r[c] without writing 301 | anything. 302 | */ 303 | template 304 | size_t medianIndex(const T* r, size_t a, size_t b, size_t c) 305 | { 306 | if (r[a] >CNT r[c]) std::swap(a, c); 307 | if (r[b] >CNT r[c]) return c; 308 | if (r[b] 318 | static size_t medianIndex(T* r, size_t a, size_t b, size_t c, size_t d) 319 | { 320 | if (r[d] =CNT r[a]) 334 | { 335 | assert(r[d] >= r[c] && r[d] >= r[a]); // so r[d] is out 336 | return medianIndex(r, a, b, c); 337 | } 338 | assert(r[a] > r[d] && r[a] > r[c]); // so r[a] is out 339 | } 340 | // Could return medianIndex(r, b, c, d) but we already know r[c] <= r[d] 341 | if (r[b] <=CNT r[c]) return c; 342 | if (r[b] >CNT r[d]) return d; 343 | return b; 344 | } 345 | 346 | /** 347 | Tukey's Ninther: compute the median of r[_1], r[_2], r[_3], then the median of 348 | r[_4], r[_5], r[_6], then the median of r[_7], r[_8], r[_9], and then swap the 349 | median of those three medians into r[_5]. 350 | */ 351 | template 352 | void ninther(T* r, size_t _1, size_t _2, size_t _3, size_t _4, size_t _5, 353 | size_t _6, size_t _7, size_t _8, size_t _9) 354 | { 355 | _2 = medianIndex(r, _1, _2, _3); 356 | _8 = medianIndex(r, _7, _8, _9); 357 | if (r[_2] >CNT r[_8]) std::swap(_2, _8); 358 | if (r[_4] >CNT r[_6]) std::swap(_4, _6); 359 | // Here we know that r[_2] and r[_8] are the other two medians and that 360 | // r[_2] <= r[_8]. We also know that r[_4] <= r[_6] 361 | if (r[_5] CNT r[_6]) 366 | { 367 | // r[_6] is the median of r[_4], r[_5], r[_6] 368 | _4 = _6; 369 | } 370 | else 371 | { 372 | // Here we know r[_5] is the median of r[_4], r[_5], r[_6] 373 | if (r[_5] CNT r[_8]) return cswap(r[_5], r[_8]); 375 | // This is the only path that returns with no swap 376 | return; 377 | } 378 | // Here we know r[_4] is the median of r[_4], r[_5], r[_6] 379 | if (r[_4] CNT r[_8]) _4 = _8; 381 | cswap(r[_5], r[_4]); 382 | } 383 | 384 | /** 385 | Input assumptions: 386 | 387 | (a) hi <= rite 388 | (c) the range r[0 .. hi] contains elements no smaller than r[0] 389 | 390 | Output guarantee: same as Hoare partition using r[0] as pivot. Returns the new 391 | position of the pivot. 392 | */ 393 | template 394 | size_t expandPartitionRight(T* r, size_t hi, size_t rite) 395 | { 396 | size_t pivot = 0; 397 | assert(pivot <= hi); 398 | assert(hi <= rite); 399 | // First loop: spend r[pivot .. hi] 400 | for (; pivot < hi; --rite) 401 | { 402 | if (rite == hi) goto done; 403 | if (r[rite] >=CNT r[0]) continue; 404 | ++pivot; 405 | assert(r[pivot] >= r[0]); 406 | cswap(r[rite], r[pivot]); 407 | } 408 | // Second loop: make left and pivot meet 409 | for (; rite > pivot; --rite) 410 | { 411 | if (r[rite] >=CNT r[0]) continue; 412 | while (rite > pivot) 413 | { 414 | ++pivot; 415 | if (r[0] 0, lo <= pivot 432 | (b) the range r[lo .. pivot] already contains elements no greater than r[pivot] 433 | 434 | Output guarantee: Same as Hoare partition around r[pivot]. Returns the new 435 | position of the pivot. 436 | 437 | */ 438 | template 439 | size_t expandPartitionLeft(T* r, size_t lo, size_t pivot) 440 | { 441 | assert(lo > 0 && lo <= pivot); 442 | size_t left = 0; 443 | const auto oldPivot = pivot; 444 | for (; lo < pivot; ++left) 445 | { 446 | if (left == lo) goto done; 447 | if (r[oldPivot] >=CNT r[left]) continue; 448 | --pivot; 449 | assert(r[oldPivot] >= r[pivot]); 450 | cswap(r[left], r[pivot]); 451 | } 452 | // Second loop: make left and pivot meet 453 | for (;; ++left) 454 | { 455 | if (left == pivot) break; 456 | if (r[oldPivot] >=CNT r[left]) continue; 457 | for (;;) 458 | { 459 | if (left == pivot) goto done; 460 | --pivot; 461 | if (r[pivot] 487 | size_t expandPartition(T* r, size_t lo, size_t pivot, size_t hi, size_t length) 488 | { 489 | assert(lo <= pivot && pivot < hi && hi <= length); 490 | --hi; 491 | --length; 492 | size_t left = 0; 493 | for (;; ++left, --length) 494 | { 495 | for (;; ++left) 496 | { 497 | if (left == lo) 498 | return pivot + 499 | expandPartitionRight(r + pivot, hi - pivot, length - pivot); 500 | if (r[left] >CNT r[pivot]) break; 501 | } 502 | for (;; --length) 503 | { 504 | if (length == hi) 505 | return left + 506 | expandPartitionLeft(r + left, lo - left, pivot - left); 507 | if (r[pivot] >=CNT r[length]) break; 508 | } 509 | cswap(r[left], r[length]); 510 | } 511 | } 512 | -------------------------------------------------------------------------------- /src/instrumented_double.h: -------------------------------------------------------------------------------- 1 | /* Copyright Andrei Alexandrescu, 2017-. 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://boost.org/LICENSE_1_0.txt) 5 | */ 6 | 7 | #pragma once 8 | 9 | #if defined(_GLIBCXX_ALGORITHM) || defined(_LIBCPP_ALGORITHM) 10 | #error Please include this file before 11 | #endif 12 | 13 | #if defined(_GLIBCXX_UTILITY) || defined(_LIBCPP_UTILITY) 14 | #error Please include this file before 15 | #endif 16 | 17 | struct Double 18 | { 19 | private: 20 | double payload; 21 | 22 | public: 23 | friend inline bool operator<(const Double& a, const Double& b) 24 | { 25 | #ifdef COUNT_COMPARISONS 26 | extern unsigned long g_comparisons; 27 | ++g_comparisons; 28 | #endif 29 | return a.payload < b.payload; 30 | } 31 | 32 | void swap(Double & b) 33 | { 34 | #ifdef COUNT_SWAPS 35 | extern unsigned long g_swaps; 36 | ++g_swaps; 37 | #endif 38 | #ifdef COUNT_WASTED_SWAPS 39 | extern unsigned long g_wastedSwaps; 40 | if (payload == b.payload) ++g_wastedSwaps; 41 | #endif 42 | auto t = payload; 43 | payload = b.payload; 44 | b.payload = t; 45 | } 46 | }; 47 | 48 | // So sue me 49 | namespace std 50 | { 51 | inline void swap(Double& a, Double& b) 52 | { 53 | a.swap(b); 54 | } 55 | } 56 | 57 | #include 58 | #ifndef _GLIBCXX_ALGORITHM 59 | #ifndef _LIBCPP_ALGORITHM 60 | #error Portability error, expecting to define _GLIBCXX_ALGORITHM or _LIBCPP_ALGORITHM 61 | #endif 62 | #endif 63 | 64 | #include 65 | #ifndef _GLIBCXX_UTILITY 66 | #ifndef _LIBCPP_UTILITY 67 | #error Portability error, expecting to define _GLIBCXX_UTILITY or _LIBCPP_UTILITY 68 | #endif 69 | #endif 70 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright Andrei Alexandrescu, 2016-. 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://boost.org/LICENSE_1_0.txt) 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "timer.h" 13 | using namespace std; 14 | 15 | extern void (*computeSelection)(double*, double*, double*); 16 | #ifdef COUNT_SWAPS 17 | unsigned long g_swaps = 0; 18 | #endif 19 | #ifdef COUNT_WASTED_SWAPS 20 | unsigned long g_wastedSwaps = 0; 21 | #endif 22 | #ifdef COUNT_COMPARISONS 23 | unsigned long g_comparisons = 0; 24 | #endif 25 | 26 | double avg(const double* b, const double*const e) 27 | { 28 | double result = 0; 29 | const double length = e - b; 30 | for (; b < e; ++b) result += *b; 31 | return result / length; 32 | } 33 | 34 | // Compute standard deviation 35 | double stddev(const double* b, const double* e, double avg) 36 | { 37 | const double size = e - b; 38 | double result = 0; 39 | for (; b != e; ++b) 40 | { 41 | auto x = *b - avg; 42 | result += x * x; 43 | } 44 | return sqrt(result / size); 45 | } 46 | 47 | int main(int argc, char** argv) 48 | { 49 | if (argc != 2) return 1; 50 | 51 | // Is this file random? If so, we should randomInput after each run 52 | const bool randomInput = strstr(argv[1], "random") != nullptr; 53 | 54 | // Figure out how many epochs we need 55 | #ifdef MEASURE_TIME 56 | const size_t epochs = 102; 57 | const size_t outlierEpochs = 2; 58 | #else 59 | const size_t epochs = randomInput ? 100 : 1; 60 | const size_t outlierEpochs = 0; 61 | #endif 62 | 63 | // Load data from input file 64 | struct stat stat_buf; 65 | if (stat(argv[1], &stat_buf) != 0) return 2; 66 | if (stat_buf.st_size == 0 || stat_buf.st_size % 8 != 0) return 3; 67 | const size_t dataLen = stat_buf.st_size / 8; 68 | auto data = new double[dataLen]; 69 | const auto f = fopen(argv[1], "rb"); 70 | if (!f) return 4; 71 | if (fread(data, sizeof(double), dataLen, f) != dataLen) return 5; 72 | if (fclose(f) != 0) return 6; 73 | 74 | // The fraction we're searching for (2 for median) 75 | const size_t frac = 2; 76 | // The order statistic we're looking for 77 | size_t index = dataLen / frac; 78 | 79 | std::random_device rd; 80 | std::mt19937 g(1); 81 | 82 | double durations[epochs]; 83 | double median = 0; 84 | #ifdef COUNT_COMPARISONS 85 | unsigned long maxComparisons = 0; 86 | #endif 87 | 88 | for (size_t i = 0; i < epochs; ++i) 89 | { 90 | if (randomInput && i > 0) 91 | shuffle(data, data + dataLen, g); 92 | 93 | vector v {data, data + dataLen}; 94 | auto b = &v[0]; 95 | 96 | #ifdef COUNT_COMPARISONS 97 | const auto tally = g_comparisons; 98 | #endif 99 | 100 | //////////////////// TIMING { 101 | Timer t; 102 | (*computeSelection)(b, b + index, b + dataLen); 103 | durations[i] = t.elapsed(); 104 | //////////////////// } TIMING 105 | 106 | // Verify consistency 107 | if (median == 0) 108 | { 109 | median = v[index]; 110 | } 111 | else 112 | { 113 | if (median != v[index]) return 7; 114 | } 115 | 116 | #ifdef COUNT_COMPARISONS 117 | maxComparisons = max(g_comparisons - tally, maxComparisons); 118 | #endif 119 | } 120 | 121 | // Verify 122 | vector v {data, data + dataLen}; 123 | sort(v.begin(), v.end()); 124 | if (median != v[index]) return 8; 125 | 126 | // Print results 127 | sort(durations, durations + epochs); 128 | 129 | #ifdef MEASURE_TIME 130 | const size_t experiments = epochs - outlierEpochs; 131 | const double avg1 = avg(durations, durations + experiments); 132 | printf("milliseconds: %g\n", avg1); 133 | const double stddev1 = stddev(durations, durations + experiments, avg1); 134 | printf("stddev: %g\n", stddev1); 135 | // Relative standard deviation 136 | printf("rsd: %g\n", stddev1 / avg1); 137 | #endif 138 | printf("size: %lu\nmedian: %g\n", dataLen, median); 139 | if (randomInput) printf("shuffled: 1\n"); 140 | #ifdef COUNT_COMPARISONS 141 | printf("comparisons: %g\n", double(g_comparisons) / (epochs * dataLen)); 142 | printf("max_comparisons: %g\n", 143 | double(maxComparisons) / dataLen); 144 | #endif 145 | #ifdef COUNT_SWAPS 146 | printf("swaps: %g\n", double(g_swaps) / (epochs * dataLen)); 147 | #endif 148 | #ifdef COUNT_WASTED_SWAPS 149 | printf("wasted_swaps: %g\n", double(g_wastedSwaps) / (epochs * dataLen)); 150 | #endif 151 | } 152 | -------------------------------------------------------------------------------- /src/median_of_ninthers.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright Andrei Alexandrescu, 2016-. 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://boost.org/LICENSE_1_0.txt) 5 | */ 6 | 7 | #include "median_of_ninthers.h" 8 | 9 | template 10 | static void quickselect(T* beg, T* mid, T* end) 11 | { 12 | if (beg == end || mid >= end) return; 13 | assert(beg <= mid && mid < end); 14 | adaptiveQuickselect(beg, mid - beg, end - beg); 15 | } 16 | 17 | void (*computeSelection)(double*, double*, double*) 18 | = &quickselect; 19 | -------------------------------------------------------------------------------- /src/median_of_ninthers.h: -------------------------------------------------------------------------------- 1 | /* Copyright Andrei Alexandrescu, 2016-. 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://boost.org/LICENSE_1_0.txt) 5 | */ 6 | 7 | #pragma once 8 | #include "common.h" 9 | #include 10 | 11 | template 12 | size_t partitionImpl(T* beg, size_t length); 13 | template 14 | void adaptiveQuickselect(T* beg, size_t n, size_t length); 15 | 16 | /** 17 | Median of minima 18 | */ 19 | template 20 | size_t medianOfMinima(T*const r, const size_t n, const size_t length) 21 | { 22 | assert(length >= 2); 23 | assert(n * 4 <= length); 24 | assert(n > 0); 25 | const size_t subset = n * 2, 26 | computeMinOver = (length - subset) / subset; 27 | assert(computeMinOver > 0); 28 | for (size_t i = 0, j = subset; i < subset; ++i) 29 | { 30 | const auto limit = j + computeMinOver; 31 | size_t minIndex = j; 32 | while (++j < limit) 33 | if (r[j] 47 | size_t medianOfMaxima(T*const r, const size_t n, const size_t length) 48 | { 49 | assert(length >= 2); 50 | assert(n * 4 >= length * 3 && n < length); 51 | const size_t subset = (length - n) * 2, 52 | subsetStart = length - subset, 53 | computeMaxOver = subsetStart / subset; 54 | assert(computeMaxOver > 0); 55 | for (size_t i = subsetStart, j = i - subset * computeMaxOver; 56 | i < length; ++i) 57 | { 58 | const auto limit = j + computeMaxOver; 59 | size_t maxIndex = j; 60 | while (++j < limit) 61 | if (r[j] >CNT r[maxIndex]) 62 | maxIndex = j; 63 | if (r[maxIndex] >CNT r[i]) 64 | cswap(r[i], r[maxIndex]); 65 | assert(j != 0 || i + 1 == length); 66 | } 67 | adaptiveQuickselect(r + subsetStart, length - n, subset); 68 | return expandPartition(r, subsetStart, n, length, length); 69 | } 70 | 71 | /** 72 | Partitions r[0 .. length] using a pivot of its own choosing. Attempts to pick a 73 | pivot that approximates the median. Returns the position of the pivot. 74 | */ 75 | template 76 | size_t medianOfNinthers(T*const r, const size_t length) 77 | { 78 | assert(length >= 12); 79 | const auto frac = 80 | length <= 1024 ? length / 12 : 81 | length <= 128 * 1024 ? length / 64 82 | : length / 1024; 83 | auto pivot = frac / 2; 84 | const auto lo = length / 2 - pivot, hi = lo + frac; 85 | assert(lo >= frac * 4); 86 | assert(length - hi >= frac * 4); 87 | assert(lo / 2 >= pivot); 88 | const auto gap = (length - 9 * frac) / 4; 89 | auto a = lo - 4 * frac - gap, b = hi + gap; 90 | for (size_t i = lo; i < hi; ++i, a += 3, b += 3) 91 | { 92 | ninther(r, a, i - frac, b, a + 1, i, b + 1, a + 2, i + frac, b + 2); 93 | } 94 | 95 | adaptiveQuickselect(r + lo, pivot, frac); 96 | return expandPartition(r, lo, lo + pivot, hi, length); 97 | } 98 | 99 | /** 100 | 101 | Quickselect driver for medianOfNinthers, medianOfMinima, and medianOfMaxima. 102 | Dispathes to each depending on the relationship between n (the sought order 103 | statistics) and length. 104 | 105 | */ 106 | template 107 | void adaptiveQuickselect(T* r, size_t n, size_t length) 108 | { 109 | assert(n < length); 110 | for (;;) 111 | { 112 | // Decide strategy for partitioning 113 | if (n == 0) 114 | { 115 | // That would be the max 116 | auto pivot = n; 117 | for (++n; n < length; ++n) 118 | if (r[n] = length * 5) 138 | pivot = medianOfMaxima(r, n, length); 139 | else 140 | pivot = medianOfNinthers(r, length); 141 | 142 | // See how the pivot fares 143 | if (pivot == n) 144 | { 145 | return; 146 | } 147 | if (pivot > n) 148 | { 149 | length = pivot; 150 | } 151 | else 152 | { 153 | ++pivot; 154 | r += pivot; 155 | length -= pivot; 156 | n -= pivot; 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/ninther.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright Andrei Alexandrescu, 2016-. 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://boost.org/LICENSE_1_0.txt) 5 | */ 6 | 7 | #include "common.h" 8 | 9 | template 10 | static T* partition(T* r, T* end) 11 | { 12 | const size_t n = end - r; 13 | size_t p; 14 | if (n >= 10) 15 | { 16 | auto k = n / 10; 17 | p = 5 * k; 18 | ninther(r, k, 2 * k, 3 * k, 4 * k, p, 6 * k, 7 * k, 8 * k, 9 * k); 19 | } 20 | else 21 | { 22 | p = n / 2; 23 | } 24 | return pivotPartition(r, p, n); 25 | } 26 | 27 | void (*computeSelection)(double*, double*, double*) 28 | = &quickselect>; 29 | -------------------------------------------------------------------------------- /src/nth_element.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright Andrei Alexandrescu, 2016-. 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://boost.org/LICENSE_1_0.txt) 5 | */ 6 | 7 | #include "instrumented_double.h" 8 | 9 | void nth_element(double* b, double* m, double* e) 10 | { 11 | return std::nth_element((Double*)b, (Double*)m, (Double*)e); 12 | } 13 | 14 | void (*computeSelection)(double*, double*, double*) 15 | = &nth_element; 16 | -------------------------------------------------------------------------------- /src/nth_element_reference.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright Andrei Alexandrescu, 2016-. 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://boost.org/LICENSE_1_0.txt) 5 | */ 6 | 7 | #include 8 | 9 | void (*computeSelection)(double*, double*, double*) 10 | = &std::nth_element; 11 | -------------------------------------------------------------------------------- /src/rnd3pivot.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright Andrei Alexandrescu, 2016-. 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://boost.org/LICENSE_1_0.txt) 5 | */ 6 | 7 | #include "common.h" 8 | #include 9 | 10 | template 11 | static T* partition(T* r, T* end) 12 | { 13 | const size_t len = end - r; 14 | assert(len >= 3); 15 | static std::mt19937 gen(1); 16 | std::uniform_int_distribution<> dis(0, len - 1); 17 | size_t x = dis(gen), y = dis(gen), z = dis(gen); 18 | return pivotPartition(r, medianIndex(r, x, y, z), len); 19 | } 20 | 21 | void (*computeSelection)(double*, double*, double*) 22 | = &quickselect>; 23 | -------------------------------------------------------------------------------- /src/timer.h: -------------------------------------------------------------------------------- 1 | /* Copyright Andrei Alexandrescu, 2016-. 2 | * Distributed under the Boost Software License, Version 1.0. 3 | * (See accompanying file LICENSE_1_0.txt or copy at 4 | * https://boost.org/LICENSE_1_0.txt) 5 | */ 6 | 7 | #pragma once 8 | #include 9 | #include 10 | 11 | class Timer 12 | { 13 | public: 14 | Timer() : beg_(clock_::now()) {} 15 | void reset() { beg_ = clock_::now(); } 16 | double elapsed() const 17 | { 18 | return std::chrono::duration_cast 19 | (clock_::now() - beg_).count(); 20 | } 21 | 22 | private: 23 | using clock_ = std::chrono::high_resolution_clock; 24 | using second_ = std::chrono::duration>; 25 | using ms_ = std::chrono::duration; 26 | std::chrono::time_point beg_; 27 | }; 28 | -------------------------------------------------------------------------------- /support/aggregate_ngrams.d: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env rdmd 2 | 3 | void main(string[] args) 4 | { 5 | import std.algorithm.searching, std.conv, std.stdio; 6 | string lastNgram; 7 | uint runningCount; 8 | foreach (line; stdin.byLine) 9 | { 10 | char[] ngram = line; 11 | line = line.find('\t'); 12 | ngram = ngram[0 .. $ - line.length]; 13 | line = line[1 .. $]; 14 | auto year = parse!uint(line); 15 | line = line[1 .. $]; 16 | auto count = parse!uint(line); 17 | if (ngram == lastNgram) 18 | { 19 | // Add to the running count 20 | runningCount += count; 21 | } 22 | else 23 | { 24 | if (lastNgram.length) 25 | writeln(lastNgram, '\t', runningCount, '\t', len(lastNgram)); 26 | runningCount = count; 27 | //delete lastNgram; 28 | lastNgram = ngram.idup; 29 | } 30 | } 31 | writeln(lastNgram, '\t', runningCount, '\t', len(lastNgram)); 32 | } 33 | 34 | size_t len(string w) 35 | { 36 | import std.range, std.string; 37 | auto i = indexOf(w, '_'); 38 | if (i != -1) w = w[0 .. i]; 39 | return w.walkLength; 40 | } 41 | -------------------------------------------------------------------------------- /support/binarize.d: -------------------------------------------------------------------------------- 1 | void main(string[] args) 2 | { 3 | import std.format, std.stdio; 4 | double x; 5 | foreach (line; stdin.byLine) 6 | { 7 | line.formattedRead("%f", &x) == 1 || assert(0); 8 | stdout.rawWrite((&x)[0 .. 1]); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /support/generate.d: -------------------------------------------------------------------------------- 1 | void main(string[] args) 2 | { 3 | import std.exception, std.getopt, std.random, std.stdio; 4 | double minValue = -300_000, maxValue = 300_000; 5 | string kind; 6 | size_t n = 10_000_000; 7 | uint seed = 1; 8 | 9 | args.getopt( 10 | "n", &n, 11 | "kind", &kind, 12 | "seed", &seed, 13 | "min", &minValue, 14 | "max", &maxValue); 15 | 16 | if (kind == "random") 17 | { 18 | auto rng = Random(seed ? seed : unpredictableSeed); 19 | foreach (i; 0 .. n) 20 | { 21 | //writeln(uniform(minValue, maxValue, rng), ','); 22 | double x = uniform(minValue, maxValue, rng); 23 | stdout.rawWrite((&x)[0 .. 1]); 24 | //import core.stdc.stdio; 25 | //fwrite(&x, x.sizeof, 1, stdout) == 1 || assert(0); 26 | } 27 | } 28 | else if (kind == "random01") 29 | { 30 | enforce(n % 2 == 0); 31 | auto rng = Random(seed ? seed : unpredictableSeed); 32 | auto a = new double[n]; 33 | a[0 .. $ / 2] = 0; 34 | a[$ / 2] = 0.5; 35 | a[$ / 2 + 1 .. $] = 1; 36 | randomShuffle(a, rng); 37 | stdout.rawWrite(a); 38 | } 39 | else if (kind == "sorted") 40 | { 41 | foreach (double i; 0 .. n) 42 | { 43 | stdout.rawWrite((&i)[0 .. 1]); 44 | } 45 | } 46 | else if (kind == "rotated") 47 | { 48 | foreach (i; 1 .. n + 1) 49 | { 50 | double x = i; 51 | stdout.rawWrite((&x)[0 .. 1]); 52 | } 53 | double last = 0; 54 | stdout.rawWrite((&last)[0 .. 1]); 55 | } 56 | else if (kind == "organpipe") 57 | { 58 | foreach (double i; 0 .. n / 2) 59 | { 60 | stdout.rawWrite((&i)[0 .. 1]); 61 | } 62 | foreach_reverse (double i; 0 .. n / 2) 63 | { 64 | stdout.rawWrite((&i)[0 .. 1]); 65 | } 66 | } 67 | else if (kind == "m3killer") 68 | { 69 | enforce((n & 3) == 0); 70 | auto k = n / 2; 71 | foreach (i; 1 .. k + 1) 72 | { 73 | if (i & 1) 74 | { 75 | double x = i; 76 | stdout.rawWrite((&x)[0 .. 1]); 77 | } 78 | else 79 | { 80 | double x = k + i - 1; 81 | stdout.rawWrite((&x)[0 .. 1]); 82 | } 83 | } 84 | foreach (i; 1 .. k + 1) 85 | { 86 | double x = 2 * i; 87 | stdout.rawWrite((&x)[0 .. 1]); 88 | } 89 | } 90 | else 91 | { 92 | enforce(0, "Must specify --kind"); 93 | } 94 | } 95 | --------------------------------------------------------------------------------