diff --git a/.vscode/settings.json b/.vscode/settings.json index 4cd077c..c5206a7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -71,6 +71,7 @@ "thread": "cpp", "cinttypes": "cpp", "typeinfo": "cpp", - "variant": "cpp" + "variant": "cpp", + "bitset": "cpp" } } \ No newline at end of file diff --git a/eval.py b/eval.py index 0a2955a..a6e01e7 100755 --- a/eval.py +++ b/eval.py @@ -9,7 +9,7 @@ def run_experiment(output_file, build_dir): # The number of threads is not currently used, it's just here in case you want to parallelize your code. for threads in [1]: # for size in [1e2, 1e3, 1e4 + 1, 1e5, 1e6 - 1, 1e7]: - for size in [1e2]: + for size in [1e2, 1e3, 1e4 + 1, 1e5, 1e7]: print("Measuring p=" + str(threads) + " n=" + str(size)) executable = Path(build_dir) / "Sorter" returncode = subprocess.call([executable, str(size), str(threads)], stdout=output_file) diff --git a/result.txt b/result.txt index e69de29..4b0b6b5 100644 --- a/result.txt +++ b/result.txt @@ -0,0 +1,5 @@ +RESULT name=sort n=100 t=1 iterations=545 durationNanoseconds=1835 totalDurationNanoseconds=1000511 constructorNanoseconds=232 totalConstructorNanoseconds=126950 +RESULT name=sort n=1000 t=1 iterations=29 durationNanoseconds=35382 totalDurationNanoseconds=1026091 constructorNanoseconds=773 totalConstructorNanoseconds=22440 +RESULT name=sort n=10001 t=1 iterations=2 durationNanoseconds=592405 totalDurationNanoseconds=1184811 constructorNanoseconds=31980 totalConstructorNanoseconds=63960 +RESULT name=sort n=100000 t=1 iterations=1 durationNanoseconds=24243178 totalDurationNanoseconds=24243178 constructorNanoseconds=562170 totalConstructorNanoseconds=562170 +RESULT name=sort n=10000000 t=1 iterations=1 durationNanoseconds=219559500741 totalDurationNanoseconds=219559500741 constructorNanoseconds=53379598 totalConstructorNanoseconds=53379598 diff --git a/src/sorter.cpp b/src/sorter.cpp index eb747f5..77093a0 100755 --- a/src/sorter.cpp +++ b/src/sorter.cpp @@ -7,15 +7,29 @@ #include #include +#define DEBUG false + namespace ae { void sorter::sort(container& data) { - // TODO Implement your sorting algorithm for (auto i = 1uz; i < data.placeholder_.size(); ++i) { std::ranges::copy(data.placeholder_[i], std::back_inserter(data.placeholder_[0])); data.placeholder_[i].clear(); } + #if DEBUG + std::vector copy; + std::ranges::copy(data.placeholder_[0], std::back_inserter(copy)); + std::sort(copy.begin(), copy.end()); + #endif sorter::msd_inplace_radix_sort(data.placeholder_[0], 0, [&](auto span) {sorter::robin_hood_sort(span);}); + + #if DEBUG + for (int i = 0; i < copy.size(); i++) { + if (copy[i] != data.placeholder_[0][i]) + std::cerr << i << " " << "sorted: " << copy[i] << " actual:" << data.placeholder_[0][i] << std::endl; + } + #endif + } void sorter::msd_inplace_radix_sort( @@ -23,10 +37,22 @@ void sorter::msd_inplace_radix_sort( size_t passes, const std::function bucket)>& bucket_sort ) { - std::cerr << "passes: " << passes << "size: " << range.size() << std::endl; + if (std::begin(range) >= std::end(range)) { + return; + } if (sorter::RADIX_ITERATIONS == passes) { - std::cerr << "going to robin " << *std::begin(range) << std::endl; - if (std::begin(range) + 1 < std::end(range)) { + switch (range.size()) { + case 1: return; + case 2: + if (range[0] >= range[1]) { + std::swap(range[0], range[1]); + } + return; + default: + bucket_sort(range); + return; + } + if (range.size() > 1) { bucket_sort(range); } return; @@ -34,60 +60,81 @@ void sorter::msd_inplace_radix_sort( auto lower = std::begin(range); auto upper = std::end(range); - - for (auto element = lower; element < upper;) { - std::cerr << *element << " " << &*element << " " << &*lower << " " << &*upper << std::endl; - // Mask out the -last bit and check if it is set - // std::cerr << std::bitset<64>((1L << (sizeof(container::element_type) * CHAR_BIT - passes - 1))) << std::endl; - // fprintf(stderr, "%lx\n", (1L << (sizeof(container::element_type) * CHAR_BIT - passes - 1))); - if ((*element & (1L << (sizeof(container::element_type) * CHAR_BIT - passes - 1)))) { - // The bit is set, so move to the beginning of the end section and decrement the upper iterator - std::swap(*upper, *element); + while (lower < upper) { + + if (*lower & (1L << (sizeof(container::element_type) * CHAR_BIT - passes - 1))) { + // The -left bit is set, so move to the beginning of the end section and decrement the upper iterator --upper; + std::swap(*upper, *lower); } else { - // The bit is unset, so move to the end of the beginning section and increment the upper iterator - std::swap(*lower, *element); ++lower; - ++element; } } - // assert(lower == upper); + #if DEBUG + std::cerr << "pass: " << passes << " begin: " << &*std::begin(range) << " end: " << &*std::end(range) << " lower: " << &*lower << std::endl; + #endif sorter::msd_inplace_radix_sort(std::span (std::begin(range), lower), passes + 1, bucket_sort); - sorter::msd_inplace_radix_sort(std::span (upper, std::end(range)), passes + 1, bucket_sort); + sorter::msd_inplace_radix_sort(std::span (lower, std::end(range)), passes + 1, bucket_sort); } void sorter::robin_hood_sort(std::span bucket) { - std::cerr << "robin hood lol" << std::endl; const auto size = bucket.size() + sorter::OVERHEAD_SIZE; const auto mask = ((1L) << (sizeof(container::element_type) * CHAR_BIT - sorter::RADIX_ITERATIONS)) - 1; - container::element_type space[size]; - std::cerr << "robin hood before loop" << std::endl; + std::vector space(size, -1L); for (auto element : bucket) { auto masked_element = (element & mask); - std::cerr << "robin hood elements " << element << " " << masked_element << " " << size << " " << mask << std::endl; - auto index = (masked_element * size) / mask; - std::cerr << "robin hood index " << index << " " << size << std::endl; + auto index = ((masked_element) * bucket.size()) / mask; if (space[index] == -1) { - space[index] = masked_element; + space[index] = element; } else { + #if DEBUG + std::cerr << "Linear probing of " << element << " at index " << index << ". Current element " << space[index] << std::endl; + #endif auto i = index; - while (i < size && space[index] != -1) {++i;}; - space[i] = masked_element; + // linear probing + while (i < size - 1 && space[i] != -1) {++i;}; + #if DEBUG + std::cerr << "Inserting " << element << " at index " << i << " instead of " << index << std::endl; + #endif + space[i] = element; } } - std::cerr << "robin hood after loop" << std::endl; + + #if DEBUG + std::cerr << "Unsorted\n"; + for (auto element : space) { + std::cerr << element << " "; + } + std::cerr << std::endl; + #endif // One final pass to correct linear probing errors for (auto i = 1; i < size; ++i) { auto j = i; - while (space[j-1] > space[j] && j > 0) { + while ((uint64_t) space[j-1] > space[j] && j > 0) { std::swap((space[j]),space[j-1]); + j--; } } + #if DEBUG + std::cerr << "Original\n"; + for (auto element : bucket) { + std::cerr << element << " "; + } + std::cerr << std::endl; + + std::cerr << "Checking if sorted\n"; + for (auto element : space) { + std::cerr << element << " "; + } + std::cerr << std::endl; + #endif + // copy data back into original range auto i = 0; for (auto element = std::begin(bucket); element < std::end(bucket); ++element) { *element = space[i]; + ++i; } } diff --git a/src/sorter.hpp b/src/sorter.hpp index 1b0d06a..bcc0925 100755 --- a/src/sorter.hpp +++ b/src/sorter.hpp @@ -17,7 +17,7 @@ class sorter { ); const uint32_t OVERHEAD_SIZE = 10L; - const uint32_t RADIX_ITERATIONS = 6; + const uint32_t RADIX_ITERATIONS = 8; void robin_hood_sort(std::span range); };