Skip to content

Commit ad788ed

Browse files
authored
Merge pull request #77 from ethz-asl/feature/adjacency_matrix_conditioning
Feature/adjacency matrix conditioning
2 parents 9047bd5 + 4726c36 commit ad788ed

File tree

6 files changed

+81
-14
lines changed

6 files changed

+81
-14
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,6 @@
3030
*.exe
3131
*.out
3232
*.app
33+
34+
# clion
35+
.idea/

polygon_coverage_geometry/include/polygon_coverage_geometry/test_comm.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,22 @@ PolygonWithHoles createSophisticatedPolygon() {
160160
return poly_with_holes;
161161
}
162162

163+
template <class Polygon>
164+
Polygon createQiangsun89Polygon() {
165+
Polygon poly;
166+
poly.push_back(Point_2(3572.0, 115.0));
167+
poly.push_back(Point_2(2724.0, 460.0));
168+
poly.push_back(Point_2(2660.0, 95.0));
169+
poly.push_back(Point_2(855.0, 813.0));
170+
poly.push_back(Point_2(1182.0, 1497.0));
171+
poly.push_back(Point_2(2925.0, 832.0));
172+
poly.push_back(Point_2(2905.0, 480.0));
173+
poly.push_back(Point_2(3608.0, 208.0));
174+
175+
return poly;
176+
}
177+
178+
163179
template <class Kernel>
164180
bool checkVerticesIdentical(const typename Kernel::Point_2& a,
165181
const typename Kernel::Point_2& b) {

polygon_coverage_geometry/src/decomposition.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ bool computeBestBCDFromPolygonWithHoles(const PolygonWithHoles& pwh,
106106

107107
// Get all possible decomposition directions.
108108
std::vector<Direction_2> directions = findPerpEdgeDirections(pwh);
109+
ROS_DEBUG("Number of perpendicular edge directions: %d", directions.size());
109110

110111
// For all possible rotations:
111112
for (const auto& dir : directions) {

polygon_coverage_geometry/test/bcd-test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
using namespace polygon_coverage_planning;
2828

29-
TEST(BctTest, computeBCD) {
29+
TEST(BcdTest, computeBCD) {
3030
// Diamond.
3131
PolygonWithHoles diamond(createDiamond<Polygon_2>());
3232
FT expected_area = diamond.outer_boundary().area();

polygon_coverage_solvers/include/polygon_coverage_solvers/graph_base.h

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -108,14 +108,6 @@ class GraphBase {
108108
// transforming cost into milli int.
109109
std::vector<std::vector<int>> getAdjacencyMatrix() const;
110110

111-
// Preserving three decimal digits.
112-
inline int doubleToMilliInt(double in) const {
113-
return static_cast<int>(std::round(in * kToMilli));
114-
}
115-
inline double milliIntToDouble(int in) const {
116-
return static_cast<double>(in) * kFromMilli;
117-
}
118-
119111
protected:
120112
// Called from addNode. Creates all edges to the node at the back of the
121113
// graph.
@@ -138,6 +130,7 @@ class GraphBase {
138130
size_t goal_idx_;
139131
bool is_created_;
140132
};
133+
141134
} // namespace polygon_coverage_planning
142135

143136
#include "polygon_coverage_solvers/impl/graph_base_impl.h"

polygon_coverage_solvers/include/polygon_coverage_solvers/impl/graph_base_impl.h

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@
2020
#ifndef POLYGON_COVERAGE_SOLVERS_GRAPH_BASE_IMPL_H_
2121
#define POLYGON_COVERAGE_SOLVERS_GRAPH_BASE_IMPL_H_
2222

23-
#include <algorithm>
24-
#include <set>
25-
2623
#include <ros/assert.h>
2724
#include <ros/console.h>
2825

26+
#include <algorithm>
27+
#include <set>
28+
2929
namespace polygon_coverage_planning {
3030

3131
template <class NodeProperty, class EdgeProperty>
@@ -324,15 +324,69 @@ Solution GraphBase<NodeProperty, EdgeProperty>::reconstructSolution(
324324
template <class NodeProperty, class EdgeProperty>
325325
std::vector<std::vector<int>>
326326
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.
327382
std::vector<std::vector<int>> m(graph_.size(),
328383
std::vector<int>(graph_.size()));
329-
330384
for (size_t i = 0; i < m.size(); ++i) {
331385
for (size_t j = 0; j < m[i].size(); ++j) {
332386
const EdgeId edge(i, j);
333387
double cost;
334388
if (edgeExists(edge) && getEdgeCost(edge, &cost)) {
335-
m[i][j] = doubleToMilliInt(cost);
389+
m[i][j] = static_cast<int>(cost * scale);
336390
} else {
337391
m[i][j] = std::numeric_limits<int>::max();
338392
}

0 commit comments

Comments
 (0)