|
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,68 @@ 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 | + // First scale the matrix such that when converting the cost to integers two |
| 328 | + // costs can always be differentiated (except for if they are the same). Find |
| 329 | + // the minimum absolute difference between any two values to normalize the |
| 330 | + // adjacency matrix. |
| 331 | + // https://afteracademy.com/blog/minimum-absolute-difference-in-an-array |
| 332 | + std::vector<double> sorted_cost; |
| 333 | + sorted_cost.reserve(graph_.size() * graph_.size()); |
| 334 | + for (size_t i = 0; i < graph_.size(); ++i) { |
| 335 | + for (size_t j = 0; j < graph_[i].size(); ++j) { |
| 336 | + const EdgeId edge(i, j); |
| 337 | + double cost; |
| 338 | + if (edgeExists(edge) && getEdgeCost(edge, &cost)) { |
| 339 | + sorted_cost.push_back(cost); |
| 340 | + } |
| 341 | + } |
| 342 | + } |
| 343 | + sort(sorted_cost.begin(), sorted_cost.end()); |
| 344 | + auto min_diff = std::numeric_limits<double>::max(); |
| 345 | + for (size_t i = 0; i < sorted_cost.size() - 2; i++) { |
| 346 | + auto diff = std::fabs(sorted_cost[i + 1] - sorted_cost[i]); |
| 347 | + if (diff > std::numeric_limits<double>::epsilon() && diff < min_diff) |
| 348 | + min_diff = diff; |
| 349 | + } |
| 350 | + |
| 351 | + // Only scale with min_diff if this does not blow up the cost. |
| 352 | + // TODO(rikba): Find a tighter upper bound. |
| 353 | + double total_cost_upper_bound = sorted_cost.back() * graph_.size(); |
| 354 | + double max_scale = 1.1 / min_diff; |
| 355 | + double min_scale = |
| 356 | + std::numeric_limits<int>::max() / (total_cost_upper_bound + 1.0); |
| 357 | + double scale = 1.0; |
| 358 | + if (max_scale * total_cost_upper_bound < std::numeric_limits<int>::max()) { |
| 359 | + ROS_DEBUG("Optimal scale applied."); |
| 360 | + scale = max_scale; |
| 361 | + } else if (min_scale * total_cost_upper_bound + 1 > |
| 362 | + std::numeric_limits<int>::max()) { |
| 363 | + // Recursive search for largest scale between min_scale and max_scale. |
| 364 | + ROS_WARN( |
| 365 | + "The adjacency matrix is ill conditioned. Adjacency matrix " |
| 366 | + "coefficients are reduced to guarantee upper cost bound. Consider " |
| 367 | + "removing small details in the polygon to have even decomposition " |
| 368 | + "size."); |
| 369 | + ROS_WARN("Recursively searching for best scale."); |
| 370 | + scale = searchLargestFeasibleScale( |
| 371 | + min_scale, max_scale, |
| 372 | + std::numeric_limits<int>::max() / total_cost_upper_bound + 1); |
| 373 | + |
| 374 | + ROS_WARN_COND(min_diff < 1.0, "Loss of optimality."); |
| 375 | + } |
| 376 | + |
| 377 | + ROS_DEBUG("The minimum cost difference is: %.9f", min_diff); |
| 378 | + ROS_INFO("The adjacency matrix scale is: %.9f", scale); |
| 379 | + |
| 380 | + // Create scale adjacency matrix. |
327 | 381 | std::vector<std::vector<int>> m(graph_.size(), |
328 | 382 | std::vector<int>(graph_.size())); |
329 | | - |
330 | 383 | for (size_t i = 0; i < m.size(); ++i) { |
331 | 384 | for (size_t j = 0; j < m[i].size(); ++j) { |
332 | 385 | const EdgeId edge(i, j); |
333 | 386 | double cost; |
334 | 387 | if (edgeExists(edge) && getEdgeCost(edge, &cost)) { |
335 | | - m[i][j] = doubleToMilliInt(cost); |
| 388 | + m[i][j] = static_cast<int>(cost * scale); |
336 | 389 | } else { |
337 | 390 | m[i][j] = std::numeric_limits<int>::max(); |
338 | 391 | } |
|
0 commit comments