Some improvements on correct behaviour.

Still some edge cases found.
This commit is contained in:
Patrick Schneider 2025-07-30 22:07:29 +02:00
parent 04789b5290
commit 15bc9836fb
5 changed files with 85 additions and 32 deletions

View File

@ -71,6 +71,7 @@
"thread": "cpp", "thread": "cpp",
"cinttypes": "cpp", "cinttypes": "cpp",
"typeinfo": "cpp", "typeinfo": "cpp",
"variant": "cpp" "variant": "cpp",
"bitset": "cpp"
} }
} }

View File

@ -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. # 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 threads in [1]:
# for size in [1e2, 1e3, 1e4 + 1, 1e5, 1e6 - 1, 1e7]: # 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)) print("Measuring p=" + str(threads) + " n=" + str(size))
executable = Path(build_dir) / "Sorter" executable = Path(build_dir) / "Sorter"
returncode = subprocess.call([executable, str(size), str(threads)], stdout=output_file) returncode = subprocess.call([executable, str(size), str(threads)], stdout=output_file)

View File

@ -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

View File

@ -7,15 +7,29 @@
#include <bitset> #include <bitset>
#include <climits> #include <climits>
#define DEBUG false
namespace ae { namespace ae {
void sorter::sort(container& data) { void sorter::sort(container& data) {
// TODO Implement your sorting algorithm
for (auto i = 1uz; i < data.placeholder_.size(); ++i) { for (auto i = 1uz; i < data.placeholder_.size(); ++i) {
std::ranges::copy(data.placeholder_[i], std::back_inserter(data.placeholder_[0])); std::ranges::copy(data.placeholder_[i], std::back_inserter(data.placeholder_[0]));
data.placeholder_[i].clear(); data.placeholder_[i].clear();
} }
#if DEBUG
std::vector<container::element_type> 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);}); 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( void sorter::msd_inplace_radix_sort(
@ -23,10 +37,22 @@ void sorter::msd_inplace_radix_sort(
size_t passes, size_t passes,
const std::function<void(std::span<container::element_type> bucket)>& bucket_sort const std::function<void(std::span<container::element_type> 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) { if (sorter::RADIX_ITERATIONS == passes) {
std::cerr << "going to robin " << *std::begin(range) << std::endl; switch (range.size()) {
if (std::begin(range) + 1 < std::end(range)) { 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); bucket_sort(range);
} }
return; return;
@ -34,60 +60,81 @@ void sorter::msd_inplace_radix_sort(
auto lower = std::begin(range); auto lower = std::begin(range);
auto upper = std::end(range); auto upper = std::end(range);
while (lower < upper) {
for (auto element = lower; element < upper;) {
std::cerr << *element << " " << &*element << " " << &*lower << " " << &*upper << std::endl; if (*lower & (1L << (sizeof(container::element_type) * CHAR_BIT - passes - 1))) {
// Mask out the <sorter::RADIX_ITERATIONS>-last bit and check if it is set // The <passes>-left bit is set, so move to the beginning of the end section and decrement the upper iterator
// 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 <passes> bit is set, so move to the beginning of the end section and decrement the upper iterator
std::swap(*upper, *element);
--upper; --upper;
std::swap(*upper, *lower);
} else { } else {
// The <passes> bit is unset, so move to the end of the beginning section and increment the upper iterator
std::swap(*lower, *element);
++lower; ++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<container::element_type> (std::begin(range), lower), passes + 1, bucket_sort); sorter::msd_inplace_radix_sort(std::span<container::element_type> (std::begin(range), lower), passes + 1, bucket_sort);
sorter::msd_inplace_radix_sort(std::span<container::element_type> (upper, std::end(range)), passes + 1, bucket_sort); sorter::msd_inplace_radix_sort(std::span<container::element_type> (lower, std::end(range)), passes + 1, bucket_sort);
} }
void sorter::robin_hood_sort(std::span<container::element_type> bucket) { void sorter::robin_hood_sort(std::span<container::element_type> bucket) {
std::cerr << "robin hood lol" << std::endl;
const auto size = bucket.size() + sorter::OVERHEAD_SIZE; const auto size = bucket.size() + sorter::OVERHEAD_SIZE;
const auto mask = ((1L) << (sizeof(container::element_type) * CHAR_BIT - sorter::RADIX_ITERATIONS)) - 1; const auto mask = ((1L) << (sizeof(container::element_type) * CHAR_BIT - sorter::RADIX_ITERATIONS)) - 1;
container::element_type space[size]; std::vector<container::element_type> space(size, -1L);
std::cerr << "robin hood before loop" << std::endl;
for (auto element : bucket) { for (auto element : bucket) {
auto masked_element = (element & mask); auto masked_element = (element & mask);
std::cerr << "robin hood elements " << element << " " << masked_element << " " << size << " " << mask << std::endl; auto index = ((masked_element) * bucket.size()) / mask;
auto index = (masked_element * size) / mask;
std::cerr << "robin hood index " << index << " " << size << std::endl;
if (space[index] == -1) { if (space[index] == -1) {
space[index] = masked_element; space[index] = element;
} else { } else {
#if DEBUG
std::cerr << "Linear probing of " << element << " at index " << index << ". Current element " << space[index] << std::endl;
#endif
auto i = index; auto i = index;
while (i < size && space[index] != -1) {++i;}; // linear probing
space[i] = masked_element; 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 // One final pass to correct linear probing errors
for (auto i = 1; i < size; ++i) { for (auto i = 1; i < size; ++i) {
auto j = 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]); 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 // copy data back into original range
auto i = 0; auto i = 0;
for (auto element = std::begin(bucket); element < std::end(bucket); ++element) { for (auto element = std::begin(bucket); element < std::end(bucket); ++element) {
*element = space[i]; *element = space[i];
++i;
} }
} }

View File

@ -17,7 +17,7 @@ class sorter {
); );
const uint32_t OVERHEAD_SIZE = 10L; const uint32_t OVERHEAD_SIZE = 10L;
const uint32_t RADIX_ITERATIONS = 6; const uint32_t RADIX_ITERATIONS = 8;
void robin_hood_sort(std::span<container::element_type> range); void robin_hood_sort(std::span<container::element_type> range);
}; };