|
20 | 20 | #ifndef POLYGON_COVERAGE_SOLVERS_GRAPH_BASE_IMPL_H_ |
21 | 21 | #define POLYGON_COVERAGE_SOLVERS_GRAPH_BASE_IMPL_H_ |
22 | 22 |
|
23 | | -#include <algorithm> |
24 | | -#include <set> |
25 | | - |
26 | 23 | #include <ros/assert.h> |
27 | 24 | #include <ros/console.h> |
28 | 25 |
|
| 26 | +#include <algorithm> |
| 27 | +#include <set> |
| 28 | + |
29 | 29 | namespace polygon_coverage_planning { |
30 | 30 |
|
31 | 31 | template <class NodeProperty, class EdgeProperty> |
@@ -324,15 +324,69 @@ Solution GraphBase<NodeProperty, EdgeProperty>::reconstructSolution( |
324 | 324 | template <class NodeProperty, class EdgeProperty> |
325 | 325 | std::vector<std::vector<int>> |
326 | 326 | GraphBase<NodeProperty, EdgeProperty>::getAdjacencyMatrix() const { |
| 327 | + ROS_DEBUG("Create adjacency matrix."); |
| 328 | + // First scale the matrix such that when converting the cost to integers two |
| 329 | + // costs can always be differentiated (except for if they are the same). Find |
| 330 | + // the minimum absolute difference between any two values to normalize the |
| 331 | + // adjacency matrix. |
| 332 | + // https://afteracademy.com/blog/minimum-absolute-difference-in-an-array |
| 333 | + std::vector<double> sorted_cost; |
| 334 | + sorted_cost.reserve(graph_.size() * graph_.size()); |
| 335 | + for (size_t i = 0; i < graph_.size(); ++i) { |
| 336 | + for (size_t j = 0; j < graph_[i].size(); ++j) { |
| 337 | + const EdgeId edge(i, j); |
| 338 | + double cost; |
| 339 | + if (edgeExists(edge) && getEdgeCost(edge, &cost)) { |
| 340 | + sorted_cost.push_back(cost); |
| 341 | + } |
| 342 | + } |
| 343 | + } |
| 344 | + sort(sorted_cost.begin(), sorted_cost.end()); |
| 345 | + const double equality = 0.000001; // Min. considered cost difference. |
| 346 | + const double min_diff_desired = 1.1; // To distinguish integer value costs. |
| 347 | + auto min_diff = min_diff_desired; |
| 348 | + if (sorted_cost.back() == 0.0) { |
| 349 | + ROS_ERROR("Adjacency matrix invalid. Greatest cost is 0.0."); |
| 350 | + min_diff = std::numeric_limits<double>::max(); |
| 351 | + } |
| 352 | + for (size_t i = 0; i < sorted_cost.size() - 1; i++) { |
| 353 | + auto diff = std::fabs(sorted_cost[i + 1] - sorted_cost[i]); |
| 354 | + if (diff > equality && diff < min_diff) min_diff = diff; |
| 355 | + } |
| 356 | + |
| 357 | + // Only scale with min_diff if this does not overflow the cost. |
| 358 | + // Maximum expected cost is number of clusters times max. cost per cluster. |
| 359 | + // TODO(rikba): Find a tighter upper bound. |
| 360 | + double total_cost_upper_bound = sorted_cost.back() * graph_.size(); |
| 361 | + double max_scale = min_diff_desired / min_diff; |
| 362 | + double min_scale = |
| 363 | + std::numeric_limits<int>::max() / (total_cost_upper_bound + 1.0); |
| 364 | + double scale = 1.0; |
| 365 | + if (max_scale * total_cost_upper_bound < std::numeric_limits<int>::max()) { |
| 366 | + ROS_DEBUG("Optimal scale %.9f applied.", max_scale); |
| 367 | + scale = max_scale; |
| 368 | + } else { |
| 369 | + ROS_DEBUG("Minimum scale %.9f applied.", min_scale); |
| 370 | + scale = min_scale; |
| 371 | + ROS_WARN_COND( |
| 372 | + min_diff < 1.0, |
| 373 | + "The adjacency matrix is ill conditioned. Consider removing small " |
| 374 | + "details in the polygon to have even decomposition sizes. Loss of " |
| 375 | + "optimality!"); |
| 376 | + } |
| 377 | + |
| 378 | + ROS_DEBUG("The minimum cost difference is: %.9f", min_diff); |
| 379 | + ROS_INFO("The adjacency matrix scale is: %.9f", scale); |
| 380 | + |
| 381 | + // Create scale adjacency matrix. |
327 | 382 | std::vector<std::vector<int>> m(graph_.size(), |
328 | 383 | std::vector<int>(graph_.size())); |
329 | | - |
330 | 384 | for (size_t i = 0; i < m.size(); ++i) { |
331 | 385 | for (size_t j = 0; j < m[i].size(); ++j) { |
332 | 386 | const EdgeId edge(i, j); |
333 | 387 | double cost; |
334 | 388 | if (edgeExists(edge) && getEdgeCost(edge, &cost)) { |
335 | | - m[i][j] = doubleToMilliInt(cost); |
| 389 | + m[i][j] = static_cast<int>(cost * scale); |
336 | 390 | } else { |
337 | 391 | m[i][j] = std::numeric_limits<int>::max(); |
338 | 392 | } |
|
0 commit comments