test_mutable_priority_queue.cpp 14 KB

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