24 #include "Eigen/Dense" 29 namespace perception {
34 static const int kHungarianOptimizerRowNotFound = -1;
35 static const int kHungarianOptimizerColNotFound = -2;
45 T*
costs(
const size_t row,
const size_t col) {
return &(costs_(row, col)); }
47 void Maximize(std::vector<std::pair<size_t, size_t>>* assignments);
48 void Minimize(std::vector<std::pair<size_t, size_t>>* assignments);
57 enum class Mark { NONE, PRIME, STAR };
62 void FindAssignments(std::vector<std::pair<size_t, size_t>>* assignments);
65 bool IsStarred(
const size_t row,
const size_t col)
const {
66 return marks_(row, col) == Mark::STAR;
70 void Star(
const size_t row,
const size_t col) {
71 marks_(row, col) = Mark::STAR;
76 void Unstar(
const size_t row,
const size_t col) {
77 marks_(row, col) = Mark::NONE;
83 int FindStarInRow(
const size_t row)
const;
87 int FindStarInCol(
const size_t col)
const;
90 bool IsPrimed(
const size_t row,
const size_t col)
const {
91 return marks_(row, col) == Mark::PRIME;
95 void Prime(
const size_t row,
const size_t col) {
96 marks_(row, col) = Mark::PRIME;
101 int FindPrimeInRow(
const size_t row)
const;
107 bool ColContainsStar(
const size_t col)
const {
108 return stars_in_col_[col] > 0;
112 bool RowCovered(
const size_t row)
const {
return rows_covered_[row]; }
115 void CoverRow(
const size_t row) { rows_covered_[row] =
true; }
118 void UncoverRow(
const size_t row) { rows_covered_[row] =
false; }
121 bool ColCovered(
const size_t col)
const {
return cols_covered_[col]; }
124 void CoverCol(
const size_t col) { cols_covered_[col] =
true; }
127 void UncoverCol(
const size_t col) { cols_covered_[col] =
false; }
133 T FindSmallestUncovered();
137 bool FindZero(
size_t* zero_row,
size_t* zero_col);
160 void CoverStarredZeroes();
178 void MakeAugmentingPath();
187 int max_optimization_size_ = 1000;
190 bool optimization_initialized_ =
false;
193 size_t matrix_size_ = 0;
202 std::vector<bool> rows_covered_;
203 std::vector<bool> cols_covered_;
209 std::vector<int> stars_in_col_;
212 std::vector<std::pair<size_t, size_t>> assignments_;
223 std::function<void()> fn_state_ =
nullptr;
225 std::vector<size_t> uncov_col_;
226 std::vector<size_t> uncov_row_;
229 template <
typename T>
232 template <
typename T>
234 : max_optimization_size_(max_optimization_size) {
235 costs_.Reserve(max_optimization_size, max_optimization_size);
236 stars_in_col_.reserve(max_optimization_size);
237 rows_covered_.reserve(max_optimization_size);
238 cols_covered_.reserve(max_optimization_size);
239 assignments_.reserve(max_optimization_size);
240 uncov_row_.reserve(max_optimization_size);
241 uncov_col_.reserve(max_optimization_size);
247 template <
typename T>
249 std::vector<std::pair<size_t, size_t>>* assignments) {
253 for (
size_t row = 0; row < height_; ++row) {
254 for (
size_t col = 0; col < width_; ++col) {
255 costs_(row, col) = max_cost_ - costs_(row, col);
258 Minimize(assignments);
264 template <
typename T>
266 std::vector<std::pair<size_t, size_t>>* assignments) {
269 FindAssignments(assignments);
273 template <
typename T>
275 if (optimization_initialized_) {
278 width_ = costs_.width();
280 height_ = costs_.height();
285 matrix_size_ = std::max(height_, width_);
291 costs_.Resize(matrix_size_, matrix_size_);
292 for (
size_t row = 0; row < matrix_size_; ++row) {
293 for (
size_t col = 0; col < matrix_size_; ++col) {
294 if ((row >= height_) || (col >= width_)) {
295 costs_(row, col) = 0;
297 max_cost_ = std::max(max_cost_, costs_(row, col));
303 marks_.Resize(matrix_size_, matrix_size_);
304 for (
size_t row = 0; row < matrix_size_; ++row) {
305 for (
size_t col = 0; col < matrix_size_; ++col) {
306 marks_(row, col) = Mark::NONE;
310 stars_in_col_.assign(matrix_size_, 0);
312 rows_covered_.assign(matrix_size_,
false);
313 cols_covered_.assign(matrix_size_,
false);
315 assignments_.resize(matrix_size_ * 2);
317 optimization_initialized_ =
true;
320 template <
typename T>
322 optimization_initialized_ =
false;
328 template <
typename T>
330 std::vector<std::pair<size_t, size_t>>* assignments) {
331 assignments->clear();
332 for (
size_t row = 0; row < height_; ++row) {
333 for (
size_t col = 0; col < width_; ++col) {
334 if (IsStarred(row, col)) {
335 assignments->push_back(std::make_pair(row, col));
344 template <
typename T>
346 for (
size_t col = 0; col < matrix_size_; ++col) {
347 if (IsStarred(row, col)) {
348 return static_cast<int>(col);
352 return kHungarianOptimizerColNotFound;
357 template <
typename T>
359 if (!ColContainsStar(col)) {
360 return kHungarianOptimizerRowNotFound;
363 for (
size_t row = 0; row < matrix_size_; ++row) {
364 if (IsStarred(row, col)) {
365 return static_cast<int>(row);
370 return kHungarianOptimizerRowNotFound;
375 template <
typename T>
377 for (
size_t col = 0; col < matrix_size_; ++col) {
378 if (IsPrimed(row, col)) {
379 return static_cast<int>(col);
383 return kHungarianOptimizerColNotFound;
387 template <
typename T>
389 for (
size_t row = 0; row < matrix_size_; ++row) {
390 for (
size_t col = 0; col < matrix_size_; ++col) {
391 if (IsPrimed(row, col)) {
392 marks_(row, col) = Mark::NONE;
399 template <
typename T>
401 for (
size_t x = 0; x < matrix_size_; x++) {
408 template <
typename T>
410 T minval = std::numeric_limits<T>::max();
414 for (
size_t i = 0; i < matrix_size_; ++i) {
415 if (!RowCovered(i)) {
416 uncov_row_.push_back(i);
418 if (!ColCovered(i)) {
419 uncov_col_.push_back(i);
423 for (
size_t row = 0; row < uncov_row_.size(); ++row) {
424 for (
size_t col = 0; col < uncov_col_.size(); ++col) {
425 minval = std::min(minval, costs_(uncov_row_[row], uncov_col_[col]));
434 template <
typename T>
439 for (
size_t i = 0; i < matrix_size_; ++i) {
440 if (!RowCovered(i)) {
441 uncov_row_.push_back(i);
443 if (!ColCovered(i)) {
444 uncov_col_.push_back(i);
447 if (uncov_row_.empty() || uncov_col_.empty()) {
451 for (
size_t i = 0; i < uncov_row_.size(); ++i) {
452 for (
size_t j = 0; j < uncov_col_.size(); ++j) {
453 if (costs_(uncov_row_[i], uncov_col_[j]) == 0) {
454 *zero_row = uncov_row_[i];
455 *zero_col = uncov_col_[j];
464 template <
typename T>
466 for (
size_t row = 0; row < matrix_size_; ++row) {
467 for (
size_t col = 0; col < matrix_size_; ++col) {
468 printf(
"%g ", costs_(row, col));
470 if (IsStarred(row, col)) {
474 if (IsPrimed(row, col)) {
483 template <
typename T>
485 int max_num_iter = 1000;
487 fn_state_ = std::bind(&HungarianOptimizer::ReduceRows,
this);
488 while (fn_state_ !=
nullptr && num_iter < max_num_iter) {
492 if (num_iter >= max_num_iter) {
497 template <
typename T>
499 for (
size_t row = 0; row < height_; ++row) {
501 bool is_single =
true;
502 for (
size_t col = 0; col < width_; ++col) {
503 if (IsStarred(row, col)) {
504 if (star_col == -1) {
513 for (
size_t col = 0; col < width_; ++col) {
523 template <
typename T>
525 for (
size_t row = 0; row < matrix_size_; ++row) {
526 T min_cost = costs_(row, 0);
527 for (
size_t col = 1; col < matrix_size_; ++col) {
528 min_cost = std::min(min_cost, costs_(row, col));
530 for (
size_t col = 0; col < matrix_size_; ++col) {
531 costs_(row, col) -= min_cost;
534 fn_state_ = std::bind(&HungarianOptimizer::StarZeroes,
this);
541 template <
typename T>
545 for (
size_t row = 0; row < matrix_size_; ++row) {
546 if (RowCovered(row)) {
549 for (
size_t col = 0; col < matrix_size_; ++col) {
550 if (ColCovered(col)) {
553 if (costs_(row, col) == 0) {
562 fn_state_ = std::bind(&HungarianOptimizer::CoverStarredZeroes,
this);
569 template <
typename T>
571 size_t num_covered = 0;
573 for (
size_t col = 0; col < matrix_size_; ++col) {
574 if (ColContainsStar(col)) {
580 if (num_covered >= matrix_size_) {
584 fn_state_ = std::bind(&HungarianOptimizer::PrimeZeroes,
this);
592 template <
typename T>
603 if (!FindZero(&zero_row, &zero_col)) {
605 fn_state_ = std::bind(&HungarianOptimizer::AugmentPath,
this);
609 Prime(zero_row, zero_col);
610 int star_col = FindStarInRow(zero_row);
612 if (star_col != kHungarianOptimizerColNotFound) {
614 UncoverCol(star_col);
616 std::pair<size_t, size_t> first_assignment =
617 std::make_pair(zero_row, zero_col);
618 assignments_[0] = first_assignment;
619 fn_state_ = std::bind(&HungarianOptimizer::MakeAugmentingPath,
this);
634 template <
typename T>
663 int row = FindStarInCol(assignments_[count].second);
665 if (row != kHungarianOptimizerRowNotFound) {
667 assignments_[count].first = row;
668 assignments_[count].second = assignments_[count - 1].second;
674 int col = FindPrimeInRow(assignments_[count].first);
676 assignments_[count].first = assignments_[count - 1].first;
677 assignments_[count].second = col;
682 for (
size_t i = 0; i <= count; ++i) {
683 size_t row = assignments_[i].first;
684 size_t col = assignments_[i].second;
686 if (IsStarred(row, col)) {
695 fn_state_ = std::bind(&HungarianOptimizer::CoverStarredZeroes,
this);
702 template <
typename T>
704 T minval = FindSmallestUncovered();
706 for (
size_t row = 0; row < matrix_size_; ++row) {
707 if (RowCovered(row)) {
708 for (
size_t c = 0; c < matrix_size_; ++c) {
709 costs_(row, c) += minval;
713 for (
size_t col = 0; col < matrix_size_; ++col) {
714 if (!ColCovered(col)) {
715 for (
size_t r = 0; r < matrix_size_; ++r) {
716 costs_(r, col) -= minval;
720 fn_state_ = std::bind(&HungarianOptimizer::PrimeZeroes,
this);
Definition: hungarian_optimizer.h:33
Definition: secure_matrix.h:29
~HungarianOptimizer()
Definition: hungarian_optimizer.h:41
PlanningContext is the runtime context in planning. It is persistent across multiple frames...
Definition: atomic_hash_map.h:25
void OptimizationClear()
Definition: hungarian_optimizer.h:321
void OptimizationInit()
Definition: hungarian_optimizer.h:274
T * costs(const size_t row, const size_t col)
Definition: hungarian_optimizer.h:45
SecureMat< T > * costs()
Definition: hungarian_optimizer.h:43
HungarianOptimizer()
Definition: hungarian_optimizer.h:230
void Maximize(std::vector< std::pair< size_t, size_t >> *assignments)
Definition: hungarian_optimizer.h:248
void PrintMatrix()
Definition: hungarian_optimizer.h:465
void Minimize(std::vector< std::pair< size_t, size_t >> *assignments)
Definition: hungarian_optimizer.h:265