1
0
Fork 0
maximum-weight-matching/cpp/test_priority_queue.cpp

253 lines
6.3 KiB
C++
Raw Normal View History

/*
* Unit tests for PriorityQueue data structure.
*
* Depends on the Boost.Test unit test framework.
* Tested with Boost v1.74, available from https://www.boost.org/
*/
#include <algorithm>
#include <climits>
#include <memory>
#include <random>
#include <string>
#include <tuple>
#include <vector>
2024-11-28 23:08:21 +01:00
#define BOOST_TEST_MODULE priority_queue
#include <boost/test/unit_test.hpp>
#include "priority_queue.hpp"
BOOST_AUTO_TEST_SUITE(test_priority_queue)
BOOST_AUTO_TEST_CASE(test_empty)
{
using Queue = mwmatching::PriorityQueue<int, std::string>;
Queue q;
BOOST_TEST(q.empty() == true);
}
BOOST_AUTO_TEST_CASE(test_single)
{
using Queue = mwmatching::PriorityQueue<int, std::string>;
Queue q;
Queue::Node n1;
BOOST_TEST(n1.valid() == false);
q.insert(&n1, 5, "a");
BOOST_TEST(n1.valid() == true);
BOOST_TEST(n1.prio() == 5);
BOOST_TEST(q.empty() == false);
BOOST_TEST(q.min_prio() == 5);
BOOST_TEST(q.min_elem() == std::string("a"));
q.set_prio(&n1, 3);
BOOST_TEST(n1.prio() == 3);
BOOST_TEST(q.min_prio() == 3);
BOOST_TEST(q.min_elem() == std::string("a"));
q.remove(&n1);
BOOST_TEST(n1.valid() == false);
BOOST_TEST(q.empty() == true);
}
BOOST_AUTO_TEST_CASE(test_simple)
{
using Queue = mwmatching::PriorityQueue<int, char>;
Queue q;
Queue::Node nodes[10];
q.insert(&nodes[0], 9, 'a');
BOOST_TEST(q.min_prio() == 9);
BOOST_TEST(q.min_elem() == 'a');
q.insert(&nodes[1], 4, 'b');
BOOST_TEST(q.min_prio() == 4);
BOOST_TEST(q.min_elem() == 'b');
q.insert(&nodes[2], 7, 'c');
BOOST_TEST(q.min_prio() == 4);
BOOST_TEST(q.min_elem() == 'b');
q.insert(&nodes[3], 5, 'd');
BOOST_TEST(q.min_prio() == 4);
BOOST_TEST(q.min_elem() == 'b');
q.insert(&nodes[4], 8, 'e');
BOOST_TEST(q.min_prio() == 4);
BOOST_TEST(q.min_elem() == 'b');
q.insert(&nodes[5], 6, 'f');
BOOST_TEST(q.min_prio() == 4);
BOOST_TEST(q.min_elem() == 'b');
q.insert(&nodes[6], 4, 'g');
q.insert(&nodes[7], 5, 'h');
q.insert(&nodes[8], 2, 'i');
BOOST_TEST(q.min_prio() == 2);
BOOST_TEST(q.min_elem() == 'i');
q.insert(&nodes[9], 6, 'j');
BOOST_TEST(q.min_prio() == 2);
BOOST_TEST(q.min_elem() == 'i');
q.set_prio(&nodes[2], 1);
BOOST_TEST(q.min_prio() == 1);
BOOST_TEST(q.min_elem() == 'c');
q.set_prio(&nodes[4], 3);
BOOST_TEST(q.min_prio() == 1);
BOOST_TEST(q.min_elem() == 'c');
q.remove(&nodes[2]);
BOOST_TEST(q.min_prio() == 2);
BOOST_TEST(q.min_elem() == 'i');
q.remove(&nodes[8]);
BOOST_TEST(q.min_prio() == 3);
BOOST_TEST(q.min_elem() == 'e');
q.remove(&nodes[4]);
q.remove(&nodes[1]);
BOOST_TEST(q.min_prio() == 4);
BOOST_TEST(q.min_elem() == 'g');
q.remove(&nodes[3]);
q.remove(&nodes[9]);
BOOST_TEST(q.min_prio() == 4);
BOOST_TEST(q.min_elem() == 'g');
q.remove(&nodes[6]);
BOOST_TEST(q.min_prio() == 5);
BOOST_TEST(q.min_elem() == 'h');
BOOST_TEST(q.empty() == false);
q.clear();
BOOST_TEST(q.empty() == true);
}
BOOST_AUTO_TEST_CASE(test_increase_prio)
{
using Queue = mwmatching::PriorityQueue<int, char>;
Queue q;
Queue::Node n1;
q.insert(&n1, 5, 'a');
q.set_prio(&n1, 8);
BOOST_TEST(n1.prio() == 8);
BOOST_TEST(q.min_prio() == 8);
q.clear();
Queue::Node n2, n3, n4;
q.insert(&n1, 9, 'A');
q.insert(&n2, 4, 'b');
q.insert(&n3, 7, 'c');
q.insert(&n4, 5, 'd');
BOOST_TEST(q.min_prio() == 4);
BOOST_TEST(q.min_elem() == 'b');
q.set_prio(&n2, 8);
BOOST_TEST(n2.prio() == 8);
BOOST_TEST(q.min_elem() == 'd');
BOOST_TEST(q.min_prio() == 5);
q.set_prio(&n3, 10);
BOOST_TEST(n3.prio() == 10);
BOOST_TEST(q.min_elem() == 'd');
q.remove(&n4);
BOOST_TEST(q.min_elem() == 'b');
q.remove(&n2);
BOOST_TEST(q.min_prio() == 9);
BOOST_TEST(q.min_elem() == 'A');
q.remove(&n1);
BOOST_TEST(q.min_elem() == 'c');
BOOST_TEST(q.min_prio() == 10);
q.remove(&n3);
BOOST_TEST(q.empty() == true);
}
BOOST_AUTO_TEST_CASE(test_random)
{
using Queue = mwmatching::PriorityQueue<int, int>;
Queue q;
const int num_elem = 1000;
std::vector<std::tuple<std::unique_ptr<Queue::Node>, int, int>> elems;
int next_data = 0;
std::mt19937 rng(34567);
auto check = [&q,&elems]() {
int min_prio = q.min_prio();
int min_data = q.min_elem();
int best_prio = INT_MAX;
bool found = false;
for (const auto& v : elems) {
int this_prio = std::get<1>(v);
int this_data = std::get<2>(v);
best_prio = std::min(best_prio, this_prio);
if ((this_prio == min_prio) && (this_data == min_data)) {
found = true;
}
}
BOOST_TEST(found == true);
BOOST_TEST(min_prio == best_prio);
};
for (int i = 0; i < num_elem; ++i) {
++next_data;
int prio = std::uniform_int_distribution<>(0, 1000000)(rng);
std::unique_ptr<Queue::Node> nptr(new Queue::Node);
q.insert(nptr.get(), prio, next_data);
elems.push_back(std::make_tuple(std::move(nptr), prio, next_data));
check();
}
for (int i = 0; i < 10000; ++i) {
int p = std::uniform_int_distribution<>(0, num_elem - 1)(rng);
Queue::Node* node = std::get<0>(elems[p]).get();
int prio = std::get<1>(elems[p]);
prio = std::uniform_int_distribution<>(0, 1000000)(rng);
q.set_prio(node, prio);
std::get<1>(elems[p]) = prio;
check();
p = std::uniform_int_distribution<>(0, num_elem - 1)(rng);
node = std::get<0>(elems[p]).get();
q.remove(node);
elems.erase(elems.begin() + p);
check();
++next_data;
prio = std::uniform_int_distribution<>(0, 1000000)(rng);
std::unique_ptr<Queue::Node> nptr(new Queue::Node);
q.insert(nptr.get(), prio, next_data);
elems.push_back(std::make_tuple(std::move(nptr), prio, next_data));
check();
}
for (int i = 0; i < num_elem; ++i) {
int p = std::uniform_int_distribution<>(0, num_elem - 1 - i)(rng);
Queue::Node* node = std::get<0>(elems[p]).get();
q.remove(node);
elems.erase(elems.begin() + p);
if (! elems.empty()) {
check();
}
}
BOOST_TEST(q.empty() == true);
}
BOOST_AUTO_TEST_SUITE_END()