// Find a 1:1 mapping from rows to columns of the specified square matrix such that the total cost is minimized. Returns a // vector V such that V[i] = j maps rows i to columns j. static std::vector<long> findMinimumAssignment(const DistanceMatrix &matrix) { #ifdef ROSE_HAVE_DLIB ASSERT_forbid(matrix.size() == 0); ASSERT_require(matrix.nr() == matrix.nc()); // We can avoid the O(n^3) Kuhn-Munkres algorithm if all values of the matrix are the same. double minValue, maxValue; dlib::find_min_and_max(matrix, minValue /*out*/, maxValue /*out*/); if (minValue == maxValue) { std::vector<long> ident; ident.reserve(matrix.nr()); for (long i=0; i<matrix.nr(); ++i) ident.push_back(i); return ident; } // Dlib's Kuhn-Munkres finds the *maximum* mapping over *integers*, so we negate everything to find the minumum, and we map // the doubles onto a reasonably large interval of integers. The interval should be large enough to have some precision, // but not so large that things might overflow. const int iGreatest = 1000000; // arbitrary upper bound for integer interval dlib::matrix<long> intMatrix(matrix.nr(), matrix.nc()); for (long i=0; i<matrix.nr(); ++i) { for (long j=0; j<matrix.nc(); ++j) intMatrix(i, j) = round(-iGreatest * (matrix(i, j) - minValue) / (maxValue - minValue)); } return dlib::max_cost_assignment(intMatrix); #else throw FunctionSimilarity::Exception("dlib support is necessary for FunctionSimilarity analysis" "; see ROSE installation instructions"); #endif }
// Given a square matrix and a 1:1 mapping from rows to columns, return the total cost of the mapping. static double totalAssignmentCost(const DistanceMatrix &matrix, const std::vector<long> assignment) { double sum = 0.0; ASSERT_require(matrix.nr() == matrix.nc()); ASSERT_require((size_t)matrix.nr() == assignment.size()); for (long i=0; i<matrix.nr(); ++i) { ASSERT_require(assignment[i] < matrix.nc()); sum += matrix(i, assignment[i]); } return sum; }