123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442 |
- #include <catch2/catch.hpp>
- #include <queue>
- #include "libslic3r/MutablePriorityQueue.hpp"
- // based on https://raw.githubusercontent.com/rollbear/prio_queue/master/self_test.cpp
- // original source Copyright Björn Fahller 2015, Boost Software License, Version 1.0, http://www.boost.org/LICENSE_1_0.txt
- TEST_CASE("Skip addressing", "[MutableSkipHeapPriorityQueue]") {
- using skip_addressing = SkipHeapAddressing<8>;
- SECTION("block root") {
- REQUIRE(skip_addressing::is_block_root(1));
- REQUIRE(skip_addressing::is_block_root(9));
- REQUIRE(skip_addressing::is_block_root(17));
- REQUIRE(skip_addressing::is_block_root(73));
- REQUIRE(! skip_addressing::is_block_root(2));
- REQUIRE(! skip_addressing::is_block_root(3));
- REQUIRE(! skip_addressing::is_block_root(4));
- REQUIRE(! skip_addressing::is_block_root(7));
- REQUIRE(! skip_addressing::is_block_root(31));
- }
- SECTION("block leaf") {
- REQUIRE(! skip_addressing::is_block_leaf(1));
- REQUIRE(! skip_addressing::is_block_leaf(2));
- REQUIRE(! skip_addressing::is_block_leaf(3));
- REQUIRE(skip_addressing::is_block_leaf(4));
- REQUIRE(skip_addressing::is_block_leaf(5));
- REQUIRE(skip_addressing::is_block_leaf(6));
- REQUIRE(skip_addressing::is_block_leaf(7));
- REQUIRE(skip_addressing::is_block_leaf(28));
- REQUIRE(skip_addressing::is_block_leaf(29));
- REQUIRE(skip_addressing::is_block_leaf(30));
- REQUIRE(! skip_addressing::is_block_leaf(257));
- REQUIRE(skip_addressing::is_block_leaf(255));
- }
- SECTION("Obtaining child") {
- REQUIRE(skip_addressing::child_of(1) == 2);
- REQUIRE(skip_addressing::child_of(2) == 4);
- REQUIRE(skip_addressing::child_of(3) == 6);
- REQUIRE(skip_addressing::child_of(4) == 9);
- REQUIRE(skip_addressing::child_of(31) == 249);
- }
- SECTION("Obtaining parent") {
- REQUIRE(skip_addressing::parent_of(2) == 1);
- REQUIRE(skip_addressing::parent_of(3) == 1);
- REQUIRE(skip_addressing::parent_of(6) == 3);
- REQUIRE(skip_addressing::parent_of(7) == 3);
- REQUIRE(skip_addressing::parent_of(9) == 4);
- REQUIRE(skip_addressing::parent_of(17) == 4);
- REQUIRE(skip_addressing::parent_of(33) == 5);
- REQUIRE(skip_addressing::parent_of(29) == 26);
- REQUIRE(skip_addressing::parent_of(1097) == 140);
- }
- }
- struct ValueIndexPair
- {
- int value;
- size_t idx = 0;
- };
- template<size_t block_size = 16>
- static auto make_test_priority_queue()
- {
- return make_miniheap_mutable_priority_queue<ValueIndexPair, block_size, false>(
- [](ValueIndexPair &v, size_t idx){ v.idx = idx; },
- [](ValueIndexPair &l, ValueIndexPair &r){ return l.value < r.value; });
- }
- TEST_CASE("Mutable priority queue - basic tests", "[MutableSkipHeapPriorityQueue]") {
- SECTION("a default constructed queue is empty") {
- auto q = make_test_priority_queue();
- REQUIRE(q.empty());
- REQUIRE(q.size() == 0);
- }
- SECTION("an empty queue is not empty when one element is inserted") {
- auto q = make_test_priority_queue();
- q.push({ 1 });
- REQUIRE(!q.empty());
- REQUIRE(q.size() == 1);
- }
- SECTION("a queue with one element has it on top") {
- auto q = make_test_priority_queue();
- q.push({ 8 });
- REQUIRE(q.top().value == 8);
- }
- SECTION("a queue with one element becomes empty when popped") {
- auto q = make_test_priority_queue();
- q.push({ 9 });
- q.pop();
- REQUIRE(q.empty());
- REQUIRE(q.size() == 0);
- }
- SECTION("insert sorted stays sorted") {
- auto q = make_test_priority_queue();
- for (auto i : { 1, 2, 3, 4, 5, 6, 7, 8 })
- q.push({ i });
- REQUIRE(q.top().value == 1);
- q.pop();
- REQUIRE(q.top().value == 2);
- q.pop();
- REQUIRE(q.top().value == 3);
- q.pop();
- REQUIRE(q.top().value == 4);
- q.pop();
- REQUIRE(q.top().value == 5);
- q.pop();
- REQUIRE(q.top().value == 6);
- q.pop();
- REQUIRE(q.top().value == 7);
- q.pop();
- REQUIRE(q.top().value == 8);
- q.pop();
- REQUIRE(q.empty());
- }
- SECTION("randomly inserted elements are popped sorted") {
- auto q = make_test_priority_queue();
- std::random_device rd;
- std::mt19937 gen(rd());
- std::uniform_int_distribution<> dist(1, 100000);
- int n[36000];
- for (auto& i : n) {
- i = dist(gen);
- q.push({ i });
- }
- REQUIRE(!q.empty());
- REQUIRE(q.size() == 36000);
- std::sort(std::begin(n), std::end(n));
- for (auto i : n) {
- REQUIRE(q.top().value == i);
- q.pop();
- }
- REQUIRE(q.empty());
- }
- }
- TEST_CASE("Mutable priority queue - reshedule first", "[MutableSkipHeapPriorityQueue]") {
- struct MyValue {
- int value;
- int *ptr;
- size_t idx;
- };
- SECTION("reschedule top with highest prio leaves order unchanged") {
- auto q = make_miniheap_mutable_priority_queue<MyValue, 4, false>(
- [](MyValue& v, size_t idx) { v.idx = idx; },
- [](MyValue& l, MyValue& r) { return l.value < r.value; });
- // 0 1 2 3 4 5 6 7 8
- int nums[] = { 32, 1, 88, 16, 9, 11, 3, 22, 23 };
- for (auto &i : nums)
- q.push({ i, &i, 0U });
- REQUIRE(q.top().value == 1);
- REQUIRE(q.top().ptr == &nums[1]);
- REQUIRE(*q.top().ptr == 1);
- // Update the top element.
- q.top().value = 2;
- q.update(1);
- REQUIRE(q.top().value == 2);
- REQUIRE(q.top().ptr == &nums[1]);
- q.pop();
- REQUIRE(q.top().value == 3);
- REQUIRE(q.top().ptr == &nums[6]);
- q.pop();
- REQUIRE(q.top().value == 9);
- REQUIRE(q.top().ptr == &nums[4]);
- q.pop();
- REQUIRE(q.top().value == 11);
- REQUIRE(q.top().ptr == &nums[5]);
- q.pop();
- REQUIRE(q.top().value == 16);
- REQUIRE(q.top().ptr == &nums[3]);
- q.pop();
- REQUIRE(q.top().value == 22);
- REQUIRE(q.top().ptr == &nums[7]);
- q.pop();
- REQUIRE(q.top().value == 23);
- REQUIRE(q.top().ptr == &nums[8]);
- q.pop();
- REQUIRE(q.top().value == 32);
- REQUIRE(q.top().ptr == &nums[0]);
- q.pop();
- REQUIRE(q.top().value == 88);
- REQUIRE(q.top().ptr == &nums[2]);
- q.pop();
- REQUIRE(q.empty());
- }
- SECTION("reschedule to mid range moves element to correct place") {
- auto q = make_miniheap_mutable_priority_queue<MyValue, 4, false>(
- [](MyValue& v, size_t idx) { v.idx = idx; },
- [](MyValue& l, MyValue& r) { return l.value < r.value; });
- // 0 1 2 3 4 5 6 7 8
- int nums[] = { 32, 1, 88, 16, 9, 11, 3, 22, 23 };
- for (auto& i : nums)
- q.push({ i, &i, 0U });
- REQUIRE(q.top().value == 1);
- REQUIRE(q.top().ptr == &nums[1]);
- REQUIRE(*q.top().ptr == 1);
- // Update the top element.
- q.top().value = 12;
- q.update(1);
- REQUIRE(q.top().value == 3);
- REQUIRE(q.top().ptr == &nums[6]);
- q.pop();
- REQUIRE(q.top().value == 9);
- REQUIRE(q.top().ptr == &nums[4]);
- q.pop();
- REQUIRE(q.top().value == 11);
- REQUIRE(q.top().ptr == &nums[5]);
- q.pop();
- REQUIRE(q.top().value == 12);
- REQUIRE(q.top().ptr == &nums[1]);
- q.pop();
- REQUIRE(q.top().value == 16);
- REQUIRE(q.top().ptr == &nums[3]);
- q.pop();
- REQUIRE(q.top().value == 22);
- REQUIRE(q.top().ptr == &nums[7]);
- q.pop();
- REQUIRE(q.top().value == 23);
- REQUIRE(q.top().ptr == &nums[8]);
- q.pop();
- REQUIRE(q.top().value == 32);
- REQUIRE(q.top().ptr == &nums[0]);
- q.pop();
- REQUIRE(q.top().value == 88);
- REQUIRE(q.top().ptr == &nums[2]);
- q.pop();
- REQUIRE(q.empty());
- }
- SECTION("reschedule to last moves element to correct place", "heap")
- {
- auto q = make_miniheap_mutable_priority_queue<MyValue, 4, false>(
- [](MyValue& v, size_t idx) { v.idx = idx; },
- [](MyValue& l, MyValue& r) { return l.value < r.value; });
- // 0 1 2 3 4 5 6 7 8
- int nums[] = { 32, 1, 88, 16, 9, 11, 3, 22, 23 };
- for (auto& i : nums)
- q.push({ i, &i, 0U });
- REQUIRE(q.top().value == 1);
- REQUIRE(q.top().ptr == &nums[1]);
- REQUIRE(*q.top().ptr == 1);
- // Update the top element.
- q.top().value = 89;
- q.update(1);
- REQUIRE(q.top().value == 3);
- REQUIRE(q.top().ptr == &nums[6]);
- q.pop();
- REQUIRE(q.top().value == 9);
- REQUIRE(q.top().ptr == &nums[4]);
- q.pop();
- REQUIRE(q.top().value == 11);
- REQUIRE(q.top().ptr == &nums[5]);
- q.pop();
- REQUIRE(q.top().value == 16);
- REQUIRE(q.top().ptr == &nums[3]);
- q.pop();
- REQUIRE(q.top().value == 22);
- REQUIRE(q.top().ptr == &nums[7]);
- q.pop();
- REQUIRE(q.top().value == 23);
- REQUIRE(q.top().ptr == &nums[8]);
- q.pop();
- REQUIRE(q.top().value == 32);
- REQUIRE(q.top().ptr == &nums[0]);
- q.pop();
- REQUIRE(q.top().value == 88);
- REQUIRE(q.top().ptr == &nums[2]);
- q.pop();
- REQUIRE(q.top().value == 89);
- REQUIRE(q.top().ptr == &nums[1]);
- q.pop();
- REQUIRE(q.empty());
- }
- SECTION("reschedule top of 2 elements to last") {
- auto q = make_test_priority_queue<8>();
- q.push({ 1 });
- q.push({ 2 });
- REQUIRE(q.top().value == 1);
- // Update the top element.
- q.top().value = 3;
- q.update(1);
- REQUIRE(q.top().value == 2);
- }
- SECTION("reschedule top of 3 elements left to 2nd") {
- auto q = make_test_priority_queue<8>();
- q.push({ 1 });
- q.push({ 2 });
- q.push({ 4 });
- REQUIRE(q.top().value == 1);
- // Update the top element.
- q.top().value = 3;
- q.update(1);
- REQUIRE(q.top().value == 2);
- }
- SECTION("reschedule top of 3 elements right to 2nd") {
- auto q = make_test_priority_queue<8>();
- q.push({ 1 });
- q.push({ 4 });
- q.push({ 2 });
- REQUIRE(q.top().value == 1);
- // Update the top element.
- q.top().value = 3;
- q.update(1);
- REQUIRE(q.top().value == 2);
- }
- SECTION("reschedule top random gives same resultas pop/push") {
- std::random_device rd;
- std::mt19937 gen(rd());
- std::uniform_int_distribution<unsigned> dist(1, 100000);
- auto pq = make_test_priority_queue<8>();
- std::priority_queue<int, std::vector<int>, std::greater<>> stdq;
- for (size_t outer = 0; outer < 100; ++ outer) {
- int num = gen();
- pq.push({ num });
- stdq.push({ num });
- for (size_t inner = 0; inner < 100; ++ inner) {
- int newval = gen();
- // Update the top element.
- pq.top().value = newval;
- pq.update(1);
- stdq.pop();
- stdq.push({ newval });
- auto n = pq.top().value;
- auto sn = stdq.top();
- REQUIRE(sn == n);
- }
- }
- }
- }
- TEST_CASE("Mutable priority queue - first pop", "[MutableSkipHeapPriorityQueue]")
- {
- struct MyValue{
- int id;
- float val;
- };
- size_t count = 50000;
- std::vector<size_t> idxs(count, {0});
- std::vector<bool> dels(count, false);
- auto q = make_miniheap_mutable_priority_queue<MyValue, 16, true>(
- [&](MyValue &v, size_t idx) {
- idxs[v.id] = idx;
- },
- [](MyValue &l, MyValue &r) { return l.val < r.val; });
- q.reserve(count);
- for (size_t id = 0; id < count; id++) {
- MyValue mv;
- mv.id = id;
- mv.val = rand();
- q.push(mv);
- }
- MyValue it = q.top(); // copy
- q.pop();
- bool valid = (it.id != 0) && (idxs[0] < 3 * count);
- CHECK(valid);
- }
- TEST_CASE("Mutable priority queue complex", "[MutableSkipHeapPriorityQueue]")
- {
- struct MyValue {
- size_t id;
- float val;
- };
- size_t count = 5000;
- std::vector<size_t> idxs(count, {0});
- std::vector<bool> dels(count, false);
- auto q = make_miniheap_mutable_priority_queue<MyValue, 16, true>(
- [&](MyValue &v, size_t idx) { idxs[v.id] = idx; },
- [](MyValue &l, MyValue &r) { return l.val < r.val; });
- q.reserve(count);
- auto rand_val = [&]()->float { return (rand() % 53) / 10.f; };
- size_t ord = 0;
- for (size_t id = 0; id < count; id++) {
- MyValue mv;
- mv.id = ord++;
- mv.val = rand_val();
- q.push(mv);
- }
- auto check = [&]()->bool{
- for (size_t i = 0; i < idxs.size(); ++i) {
- if (dels[i]) continue;
- size_t qid = idxs[i];
- if (qid > 3*count) {
- return false;
- }
- MyValue &mv = q[qid];
- if (mv.id != i) {
- return false; // ERROR
- }
- }
- return true;
- };
- CHECK(check()); // initial check
- auto get_valid_id = [&]()->int {
- int id = 0;
- do {
- id = rand() % count;
- } while (dels[id]);
- return id;
- };
- for (size_t i = 0; i < 100; i++) {
- MyValue it = q.top(); // copy
- q.pop();
- dels[it.id] = true;
- CHECK(check());
- if (i % 20 == 0) {
- it.val = rand_val();
- q.push(it);
- dels[it.id] = false;
- CHECK(check());
- continue;
- }
- int id = get_valid_id();
- q.remove(idxs[id]);
- dels[id] = true;
- CHECK(check());
- for (size_t j = 0; j < 5; j++) {
- int id = get_valid_id();
- size_t qid = idxs[id];
- MyValue &mv = q[qid];
- mv.val = rand_val();
- q.update(qid);
- CHECK(check());
- }
- }
- }
|