Test Munkres assignment algorithm.
#include <visp3/core/vpMunkres.h>
#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_17) && \
(!defined(_MSC_VER) || ( (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_17) && (_MSC_VER >= 1911) ) )
#include <iostream>
{
ostream &operator<<(ostream &os, const pair<unsigned int, unsigned int> &val)
{
os << "[" << val.first << "," << val.second << "]";
return os;
}
}
#ifdef VISP_HAVE_CATCH2
#define CATCH_CONFIG_RUNNER
#include <catch.hpp>
TEST_CASE("Check Munkres-based assignment", "[visp_munkres]")
{
auto testMunkres = [](const std::vector<std::vector<double> > &cost_matrix,
const std::vector<std::pair<unsigned int, unsigned int> > &expected_pairs) {
REQUIRE(expected_pairs.size() == munkres_pairs.size());
for (auto i = 0u; i < munkres_pairs.size(); i++) {
REQUIRE(expected_pairs.at(i) == munkres_pairs.at(i));
}
};
SECTION("Square cost matrix")
{
std::vector<std::vector<double> > costs{};
costs.push_back(std::vector<double>{3, 1, 2});
costs.push_back(std::vector<double>{2, 3, 1});
costs.push_back(std::vector<double>{1, 2, 3});
std::vector<std::pair<unsigned int, unsigned int> > expected_pairs{};
expected_pairs.emplace_back(0, 1);
expected_pairs.emplace_back(1, 2);
expected_pairs.emplace_back(2, 0);
testMunkres(costs, expected_pairs);
}
SECTION("Horizontal cost matrix")
{
std::vector<std::vector<double> > costs{};
costs.push_back(std::vector<double>{4, 1, 2, 3});
costs.push_back(std::vector<double>{3, 4, 1, 2});
costs.push_back(std::vector<double>{2, 3, 4, 1});
std::vector<std::pair<unsigned int, unsigned int> > expected_pairs{};
expected_pairs.emplace_back(0, 1);
expected_pairs.emplace_back(1, 2);
expected_pairs.emplace_back(2, 3);
testMunkres(costs, expected_pairs);
}
SECTION("Vertical cost matrix")
{
std::vector<std::vector<double> > costs{};
costs.push_back(std::vector<double>{4, 1, 2});
costs.push_back(std::vector<double>{3, 4, 1});
costs.push_back(std::vector<double>{2, 3, 4});
costs.push_back(std::vector<double>{1, 2, 3});
std::vector<std::pair<unsigned int, unsigned int> > expected_pairs{};
expected_pairs.emplace_back(0, 1);
expected_pairs.emplace_back(1, 2);
expected_pairs.emplace_back(3, 0);
testMunkres(costs, expected_pairs);
}
}
int main(int argc, char *argv[])
{
Catch::Session session;
session.applyCommandLine(argc, argv);
return session.run();
}
#else
bool testMunkres(const std::vector<std::vector<double> > &costs_matrix,
const std::vector<std::pair<unsigned int, unsigned int> > &expected_pairs)
{
if (pairs.size() != expected_pairs.size()) {
std::cerr << "Expected nb of association | Munkres nb of association: "
<< expected_pairs.size() << " | " << pairs.size()
<< std::endl;
return false;
}
for (auto i = 0u; i < pairs.size(); i++) {
if (expected_pairs.at(i) != pairs.at(i)) {
std::cout << "Cost matrix:" << std::endl;
for (const auto &cost_row : costs_matrix) {
std::cout << "| ";
for (const auto &cost : cost_row) {
std::cout << cost << " | ";
}
std::cout << std::endl;
}
std::cout << std::endl;
std::cerr << "FAIL: "
<< "Expected association | Munkres association: " << expected_pairs.at(i) << " | " << pairs.at(i)
<< std::endl;
return false;
}
}
return true;
}
bool testSquareMat()
{
std::vector<std::vector<double> > costs{};
costs.push_back(std::vector<double>{3, 4, 1, 2});
costs.push_back(std::vector<double>{3, 4, 2, 1});
costs.push_back(std::vector<double>{1, 2, 3, 4});
costs.push_back(std::vector<double>{2, 1, 4, 3});
std::vector<std::pair<unsigned int, unsigned int> > pairs{};
pairs.emplace_back(0, 2);
pairs.emplace_back(1, 3);
pairs.emplace_back(2, 0);
pairs.emplace_back(3, 1);
return testMunkres(costs, pairs);
}
bool testVertMat()
{
std::vector<std::vector<double> > costs{};
costs.push_back(std::vector<double>{3, 2, 1});
costs.push_back(std::vector<double>{4, 3, 2});
costs.push_back(std::vector<double>{1, 4, 3});
costs.push_back(std::vector<double>{2, 1, 4});
std::vector<std::pair<unsigned int, unsigned int> > pairs{};
pairs.emplace_back(0, 2);
pairs.emplace_back(2, 0);
pairs.emplace_back(3, 1);
return testMunkres(costs, pairs);
}
bool testHorMat()
{
std::vector<std::vector<double> > costs{};
costs.push_back(std::vector<double>{2, 3, 4, 1});
costs.push_back(std::vector<double>{4, 1, 2, 3});
costs.push_back(std::vector<double>{1, 2, 3, 4});
std::vector<std::pair<unsigned int, unsigned int> > pairs{};
pairs.emplace_back(0, 3);
pairs.emplace_back(1, 1);
pairs.emplace_back(2, 0);
return testMunkres(costs, pairs);
}
int main()
{
if (not testSquareMat()) {
return EXIT_FAILURE;
}
if (not testVertMat()) {
return EXIT_FAILURE;
}
if (not testHorMat()) {
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
#endif
#else
int main() { return EXIT_SUCCESS; }
#endif