test_mutable_priority_queue.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. #include <catch2/catch.hpp>
  2. #include <queue>
  3. #include "libslic3r/MutablePriorityQueue.hpp"
  4. using namespace Slic3r;
  5. // based on https://raw.githubusercontent.com/rollbear/prio_queue/master/self_test.cpp
  6. // original source Copyright Björn Fahller 2015, Boost Software License, Version 1.0, http://www.boost.org/LICENSE_1_0.txt
  7. TEST_CASE("Skip addressing", "[MutableSkipHeapPriorityQueue]") {
  8. using skip_addressing = SkipHeapAddressing<8>;
  9. SECTION("block root") {
  10. REQUIRE(skip_addressing::is_block_root(1));
  11. REQUIRE(skip_addressing::is_block_root(9));
  12. REQUIRE(skip_addressing::is_block_root(17));
  13. REQUIRE(skip_addressing::is_block_root(73));
  14. REQUIRE(! skip_addressing::is_block_root(2));
  15. REQUIRE(! skip_addressing::is_block_root(3));
  16. REQUIRE(! skip_addressing::is_block_root(4));
  17. REQUIRE(! skip_addressing::is_block_root(7));
  18. REQUIRE(! skip_addressing::is_block_root(31));
  19. }
  20. SECTION("block leaf") {
  21. REQUIRE(! skip_addressing::is_block_leaf(1));
  22. REQUIRE(! skip_addressing::is_block_leaf(2));
  23. REQUIRE(! skip_addressing::is_block_leaf(3));
  24. REQUIRE(skip_addressing::is_block_leaf(4));
  25. REQUIRE(skip_addressing::is_block_leaf(5));
  26. REQUIRE(skip_addressing::is_block_leaf(6));
  27. REQUIRE(skip_addressing::is_block_leaf(7));
  28. REQUIRE(skip_addressing::is_block_leaf(28));
  29. REQUIRE(skip_addressing::is_block_leaf(29));
  30. REQUIRE(skip_addressing::is_block_leaf(30));
  31. REQUIRE(! skip_addressing::is_block_leaf(257));
  32. REQUIRE(skip_addressing::is_block_leaf(255));
  33. }
  34. SECTION("Obtaining child") {
  35. REQUIRE(skip_addressing::child_of(1) == 2);
  36. REQUIRE(skip_addressing::child_of(2) == 4);
  37. REQUIRE(skip_addressing::child_of(3) == 6);
  38. REQUIRE(skip_addressing::child_of(4) == 9);
  39. REQUIRE(skip_addressing::child_of(31) == 249);
  40. }
  41. SECTION("Obtaining parent") {
  42. REQUIRE(skip_addressing::parent_of(2) == 1);
  43. REQUIRE(skip_addressing::parent_of(3) == 1);
  44. REQUIRE(skip_addressing::parent_of(6) == 3);
  45. REQUIRE(skip_addressing::parent_of(7) == 3);
  46. REQUIRE(skip_addressing::parent_of(9) == 4);
  47. REQUIRE(skip_addressing::parent_of(17) == 4);
  48. REQUIRE(skip_addressing::parent_of(33) == 5);
  49. REQUIRE(skip_addressing::parent_of(29) == 26);
  50. REQUIRE(skip_addressing::parent_of(1097) == 140);
  51. }
  52. }
  53. struct ValueIndexPair
  54. {
  55. int value;
  56. size_t idx = 0;
  57. };
  58. template<size_t block_size = 16>
  59. static auto make_test_priority_queue()
  60. {
  61. return make_miniheap_mutable_priority_queue<ValueIndexPair, block_size, false>(
  62. [](ValueIndexPair &v, size_t idx){ v.idx = idx; },
  63. [](ValueIndexPair &l, ValueIndexPair &r){ return l.value < r.value; });
  64. }
  65. TEST_CASE("Mutable priority queue - basic tests", "[MutableSkipHeapPriorityQueue]") {
  66. SECTION("a default constructed queue is empty") {
  67. auto q = make_test_priority_queue();
  68. REQUIRE(q.empty());
  69. REQUIRE(q.size() == 0);
  70. }
  71. SECTION("an empty queue is not empty when one element is inserted") {
  72. auto q = make_test_priority_queue();
  73. q.push({ 1 });
  74. REQUIRE(!q.empty());
  75. REQUIRE(q.size() == 1);
  76. }
  77. SECTION("a queue with one element has it on top") {
  78. auto q = make_test_priority_queue();
  79. q.push({ 8 });
  80. REQUIRE(q.top().value == 8);
  81. }
  82. SECTION("a queue with one element becomes empty when popped") {
  83. auto q = make_test_priority_queue();
  84. q.push({ 9 });
  85. q.pop();
  86. REQUIRE(q.empty());
  87. REQUIRE(q.size() == 0);
  88. }
  89. SECTION("insert sorted stays sorted") {
  90. auto q = make_test_priority_queue();
  91. for (auto i : { 1, 2, 3, 4, 5, 6, 7, 8 })
  92. q.push({ i });
  93. REQUIRE(q.top().value == 1);
  94. q.pop();
  95. REQUIRE(q.top().value == 2);
  96. q.pop();
  97. REQUIRE(q.top().value == 3);
  98. q.pop();
  99. REQUIRE(q.top().value == 4);
  100. q.pop();
  101. REQUIRE(q.top().value == 5);
  102. q.pop();
  103. REQUIRE(q.top().value == 6);
  104. q.pop();
  105. REQUIRE(q.top().value == 7);
  106. q.pop();
  107. REQUIRE(q.top().value == 8);
  108. q.pop();
  109. REQUIRE(q.empty());
  110. }
  111. SECTION("randomly inserted elements are popped sorted") {
  112. auto q = make_test_priority_queue();
  113. std::random_device rd;
  114. std::mt19937 gen(rd());
  115. std::uniform_int_distribution<> dist(1, 100000);
  116. int n[36000];
  117. for (auto& i : n) {
  118. i = dist(gen);
  119. q.push({ i });
  120. }
  121. REQUIRE(!q.empty());
  122. REQUIRE(q.size() == 36000);
  123. std::sort(std::begin(n), std::end(n));
  124. for (auto i : n) {
  125. REQUIRE(q.top().value == i);
  126. q.pop();
  127. }
  128. REQUIRE(q.empty());
  129. }
  130. }
  131. TEST_CASE("Mutable priority queue - reshedule first", "[MutableSkipHeapPriorityQueue]") {
  132. struct MyValue {
  133. int value;
  134. int *ptr;
  135. size_t idx;
  136. };
  137. SECTION("reschedule top with highest prio leaves order unchanged") {
  138. auto q = make_miniheap_mutable_priority_queue<MyValue, 4, false>(
  139. [](MyValue& v, size_t idx) { v.idx = idx; },
  140. [](MyValue& l, MyValue& r) { return l.value < r.value; });
  141. // 0 1 2 3 4 5 6 7 8
  142. int nums[] = { 32, 1, 88, 16, 9, 11, 3, 22, 23 };
  143. for (auto &i : nums)
  144. q.push({ i, &i, 0U });
  145. REQUIRE(q.top().value == 1);
  146. REQUIRE(q.top().ptr == &nums[1]);
  147. REQUIRE(*q.top().ptr == 1);
  148. // Update the top element.
  149. q.top().value = 2;
  150. q.update(1);
  151. REQUIRE(q.top().value == 2);
  152. REQUIRE(q.top().ptr == &nums[1]);
  153. q.pop();
  154. REQUIRE(q.top().value == 3);
  155. REQUIRE(q.top().ptr == &nums[6]);
  156. q.pop();
  157. REQUIRE(q.top().value == 9);
  158. REQUIRE(q.top().ptr == &nums[4]);
  159. q.pop();
  160. REQUIRE(q.top().value == 11);
  161. REQUIRE(q.top().ptr == &nums[5]);
  162. q.pop();
  163. REQUIRE(q.top().value == 16);
  164. REQUIRE(q.top().ptr == &nums[3]);
  165. q.pop();
  166. REQUIRE(q.top().value == 22);
  167. REQUIRE(q.top().ptr == &nums[7]);
  168. q.pop();
  169. REQUIRE(q.top().value == 23);
  170. REQUIRE(q.top().ptr == &nums[8]);
  171. q.pop();
  172. REQUIRE(q.top().value == 32);
  173. REQUIRE(q.top().ptr == &nums[0]);
  174. q.pop();
  175. REQUIRE(q.top().value == 88);
  176. REQUIRE(q.top().ptr == &nums[2]);
  177. q.pop();
  178. REQUIRE(q.empty());
  179. }
  180. SECTION("reschedule to mid range moves element to correct place") {
  181. auto q = make_miniheap_mutable_priority_queue<MyValue, 4, false>(
  182. [](MyValue& v, size_t idx) { v.idx = idx; },
  183. [](MyValue& l, MyValue& r) { return l.value < r.value; });
  184. // 0 1 2 3 4 5 6 7 8
  185. int nums[] = { 32, 1, 88, 16, 9, 11, 3, 22, 23 };
  186. for (auto& i : nums)
  187. q.push({ i, &i, 0U });
  188. REQUIRE(q.top().value == 1);
  189. REQUIRE(q.top().ptr == &nums[1]);
  190. REQUIRE(*q.top().ptr == 1);
  191. // Update the top element.
  192. q.top().value = 12;
  193. q.update(1);
  194. REQUIRE(q.top().value == 3);
  195. REQUIRE(q.top().ptr == &nums[6]);
  196. q.pop();
  197. REQUIRE(q.top().value == 9);
  198. REQUIRE(q.top().ptr == &nums[4]);
  199. q.pop();
  200. REQUIRE(q.top().value == 11);
  201. REQUIRE(q.top().ptr == &nums[5]);
  202. q.pop();
  203. REQUIRE(q.top().value == 12);
  204. REQUIRE(q.top().ptr == &nums[1]);
  205. q.pop();
  206. REQUIRE(q.top().value == 16);
  207. REQUIRE(q.top().ptr == &nums[3]);
  208. q.pop();
  209. REQUIRE(q.top().value == 22);
  210. REQUIRE(q.top().ptr == &nums[7]);
  211. q.pop();
  212. REQUIRE(q.top().value == 23);
  213. REQUIRE(q.top().ptr == &nums[8]);
  214. q.pop();
  215. REQUIRE(q.top().value == 32);
  216. REQUIRE(q.top().ptr == &nums[0]);
  217. q.pop();
  218. REQUIRE(q.top().value == 88);
  219. REQUIRE(q.top().ptr == &nums[2]);
  220. q.pop();
  221. REQUIRE(q.empty());
  222. }
  223. SECTION("reschedule to last moves element to correct place", "heap")
  224. {
  225. auto q = make_miniheap_mutable_priority_queue<MyValue, 4, false>(
  226. [](MyValue& v, size_t idx) { v.idx = idx; },
  227. [](MyValue& l, MyValue& r) { return l.value < r.value; });
  228. // 0 1 2 3 4 5 6 7 8
  229. int nums[] = { 32, 1, 88, 16, 9, 11, 3, 22, 23 };
  230. for (auto& i : nums)
  231. q.push({ i, &i, 0U });
  232. REQUIRE(q.top().value == 1);
  233. REQUIRE(q.top().ptr == &nums[1]);
  234. REQUIRE(*q.top().ptr == 1);
  235. // Update the top element.
  236. q.top().value = 89;
  237. q.update(1);
  238. REQUIRE(q.top().value == 3);
  239. REQUIRE(q.top().ptr == &nums[6]);
  240. q.pop();
  241. REQUIRE(q.top().value == 9);
  242. REQUIRE(q.top().ptr == &nums[4]);
  243. q.pop();
  244. REQUIRE(q.top().value == 11);
  245. REQUIRE(q.top().ptr == &nums[5]);
  246. q.pop();
  247. REQUIRE(q.top().value == 16);
  248. REQUIRE(q.top().ptr == &nums[3]);
  249. q.pop();
  250. REQUIRE(q.top().value == 22);
  251. REQUIRE(q.top().ptr == &nums[7]);
  252. q.pop();
  253. REQUIRE(q.top().value == 23);
  254. REQUIRE(q.top().ptr == &nums[8]);
  255. q.pop();
  256. REQUIRE(q.top().value == 32);
  257. REQUIRE(q.top().ptr == &nums[0]);
  258. q.pop();
  259. REQUIRE(q.top().value == 88);
  260. REQUIRE(q.top().ptr == &nums[2]);
  261. q.pop();
  262. REQUIRE(q.top().value == 89);
  263. REQUIRE(q.top().ptr == &nums[1]);
  264. q.pop();
  265. REQUIRE(q.empty());
  266. }
  267. SECTION("reschedule top of 2 elements to last") {
  268. auto q = make_test_priority_queue<8>();
  269. q.push({ 1 });
  270. q.push({ 2 });
  271. REQUIRE(q.top().value == 1);
  272. // Update the top element.
  273. q.top().value = 3;
  274. q.update(1);
  275. REQUIRE(q.top().value == 2);
  276. }
  277. SECTION("reschedule top of 3 elements left to 2nd") {
  278. auto q = make_test_priority_queue<8>();
  279. q.push({ 1 });
  280. q.push({ 2 });
  281. q.push({ 4 });
  282. REQUIRE(q.top().value == 1);
  283. // Update the top element.
  284. q.top().value = 3;
  285. q.update(1);
  286. REQUIRE(q.top().value == 2);
  287. }
  288. SECTION("reschedule top of 3 elements right to 2nd") {
  289. auto q = make_test_priority_queue<8>();
  290. q.push({ 1 });
  291. q.push({ 4 });
  292. q.push({ 2 });
  293. REQUIRE(q.top().value == 1);
  294. // Update the top element.
  295. q.top().value = 3;
  296. q.update(1);
  297. REQUIRE(q.top().value == 2);
  298. }
  299. SECTION("reschedule top random gives same resultas pop/push") {
  300. std::random_device rd;
  301. std::mt19937 gen(rd());
  302. std::uniform_int_distribution<unsigned> dist(1, 100000);
  303. auto pq = make_test_priority_queue<8>();
  304. std::priority_queue<int, std::vector<int>, std::greater<>> stdq;
  305. for (size_t outer = 0; outer < 100; ++ outer) {
  306. int num = gen();
  307. pq.push({ num });
  308. stdq.push({ num });
  309. for (size_t inner = 0; inner < 100; ++ inner) {
  310. int newval = gen();
  311. // Update the top element.
  312. pq.top().value = newval;
  313. pq.update(1);
  314. stdq.pop();
  315. stdq.push({ newval });
  316. auto n = pq.top().value;
  317. auto sn = stdq.top();
  318. REQUIRE(sn == n);
  319. }
  320. }
  321. }
  322. }
  323. TEST_CASE("Mutable priority queue - first pop", "[MutableSkipHeapPriorityQueue]")
  324. {
  325. struct MyValue{
  326. size_t id;
  327. float val;
  328. };
  329. static constexpr const size_t count = 50000;
  330. std::vector<size_t> idxs(count, {0});
  331. auto q = make_miniheap_mutable_priority_queue<MyValue, 16, true>(
  332. [&idxs](MyValue &v, size_t idx) { idxs[v.id] = idx; },
  333. [](MyValue &l, MyValue &r) { return l.val < r.val; });
  334. using QueueType = decltype(q);
  335. THEN("Skip queue has 0th element unused, 1st element is the top of the queue.") {
  336. CHECK(QueueType::address::is_padding(0));
  337. CHECK(!QueueType::address::is_padding(1));
  338. }
  339. q.reserve(count);
  340. for (size_t id = 0; id < count; ++ id)
  341. q.push({ id, rand() / 100.f });
  342. MyValue v = q.top(); // copy
  343. THEN("Element at the top of the queue has a valid ID.") {
  344. CHECK(v.id >= 0);
  345. CHECK(v.id < count);
  346. }
  347. THEN("Element at the top of the queue has its position stored in idxs.") {
  348. CHECK(idxs[v.id] == 1);
  349. }
  350. q.pop();
  351. THEN("Element removed from the queue has its position in idxs reset to invalid.") {
  352. CHECK(idxs[v.id] == q.invalid_id());
  353. }
  354. THEN("Element was removed from the queue, new top of the queue has its index set correctly.") {
  355. CHECK(q.top().id >= 0);
  356. CHECK(q.top().id < count);
  357. CHECK(idxs[q.top().id] == 1);
  358. }
  359. }
  360. TEST_CASE("Mutable priority queue complex", "[MutableSkipHeapPriorityQueue]")
  361. {
  362. struct MyValue {
  363. size_t id;
  364. float val;
  365. };
  366. size_t count = 5000;
  367. std::vector<size_t> idxs(count, {0});
  368. std::vector<bool> dels(count, false);
  369. auto q = make_miniheap_mutable_priority_queue<MyValue, 16, true>(
  370. [&](MyValue &v, size_t idx) { idxs[v.id] = idx; },
  371. [](MyValue &l, MyValue &r) { return l.val < r.val; });
  372. q.reserve(count);
  373. auto rand_val = [&]()->float { return (rand() % 53) / 10.f; };
  374. for (size_t id = 0; id < count; ++ id)
  375. q.push({ id, rand_val() });
  376. auto check = [&]()->bool{
  377. for (size_t i = 0; i < idxs.size(); ++i) {
  378. if (dels[i]) {
  379. if (idxs[i] != q.invalid_id())
  380. return false; // ERROR
  381. } else {
  382. size_t qid = idxs[i];
  383. if (qid >= q.heap_size()) {
  384. return false; // ERROR
  385. }
  386. MyValue &mv = q[qid];
  387. if (mv.id != i) {
  388. return false; // ERROR
  389. }
  390. }
  391. }
  392. return true;
  393. };
  394. CHECK(check()); // initial check
  395. // Generate an element ID of an elmenet, which was not yet deleted, thus it is still valid.
  396. auto get_valid_id = [&]()->int {
  397. int id = 0;
  398. do {
  399. id = rand() % count;
  400. } while (dels[id]);
  401. return id;
  402. };
  403. // Remove first 100 elements from the queue of 5000 elements, cross-validate indices.
  404. // Re-enter every 20th element back to the queue.
  405. for (size_t i = 0; i < 100; i++) {
  406. MyValue v = q.top(); // copy
  407. q.pop();
  408. dels[v.id] = true;
  409. CHECK(check());
  410. if (i % 20 == 0) {
  411. v.val = rand_val();
  412. q.push(v);
  413. dels[v.id] = false;
  414. CHECK(check());
  415. continue;
  416. }
  417. // Remove some valid element from the queue.
  418. int id = get_valid_id();
  419. CHECK(idxs[id] != q.invalid_id());
  420. q.remove(idxs[id]);
  421. dels[id] = true;
  422. CHECK(check());
  423. // and change 5 random elements and reorder them in the queue.
  424. for (size_t j = 0; j < 5; j++) {
  425. int id = get_valid_id();
  426. size_t qid = idxs[id];
  427. MyValue &mv = q[qid];
  428. mv.val = rand_val();
  429. q.update(qid);
  430. CHECK(check());
  431. }
  432. }
  433. }