OR-Tools  8.1
hungarian.cc
Go to the documentation of this file.
1 // Copyright 2010-2018 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 // See: //depot/google3/java/com/google/wireless/genie/frontend
15 // /mixer/matching/HungarianOptimizer.java
16 
18 
19 #include <algorithm>
20 #include <cstdio>
21 #include <limits>
22 
23 #include "absl/strings/str_format.h"
24 #include "ortools/base/logging.h"
25 
26 namespace operations_research {
27 
29  static constexpr int kHungarianOptimizerRowNotFound = -1;
30  static constexpr int kHungarianOptimizerColNotFound = -2;
31 
32  public:
33  // Setup the initial conditions for the algorithm.
34 
35  // Parameters: costs is a matrix of the cost of assigning each agent to
36  // each task. costs[i][j] is the cost of assigning agent i to task j.
37  // All the costs must be non-negative. This matrix does not have to
38  // be square (i.e. we can have different numbers of agents and tasks), but it
39  // must be regular (i.e. there must be the same number of entries in each row
40  // of the matrix).
41  explicit HungarianOptimizer(const std::vector<std::vector<double>>& costs);
42 
43  // Find an assignment which maximizes the total cost.
44  // Returns the assignment in the two vectors passed as argument.
45  // preimage[i] is assigned to image[i].
46  void Maximize(std::vector<int>* preimage, std::vector<int>* image);
47 
48  // Like Maximize(), but minimizing the cost instead.
49  void Minimize(std::vector<int>* preimage, std::vector<int>* image);
50 
51  private:
52  typedef void (HungarianOptimizer::*Step)();
53 
54  typedef enum { NONE, PRIME, STAR } Mark;
55 
56  // Convert the final cost matrix into a set of assignments of preimage->image.
57  // Returns the assignment in the two vectors passed as argument, the same as
58  // Minimize and Maximize
59  void FindAssignments(std::vector<int>* preimage, std::vector<int>* image);
60 
61  // Is the cell (row, col) starred?
62  bool IsStarred(int row, int col) const { return marks_[row][col] == STAR; }
63 
64  // Mark cell (row, col) with a star
65  void Star(int row, int col) {
66  marks_[row][col] = STAR;
67  stars_in_col_[col]++;
68  }
69 
70  // Remove a star from cell (row, col)
71  void UnStar(int row, int col) {
72  marks_[row][col] = NONE;
73  stars_in_col_[col]--;
74  }
75 
76  // Find a column in row 'row' containing a star, or return
77  // kHungarianOptimizerColNotFound if no such column exists.
78  int FindStarInRow(int row) const;
79 
80  // Find a row in column 'col' containing a star, or return
81  // kHungarianOptimizerRowNotFound if no such row exists.
82  int FindStarInCol(int col) const;
83 
84  // Is cell (row, col) marked with a prime?
85  bool IsPrimed(int row, int col) const { return marks_[row][col] == PRIME; }
86 
87  // Mark cell (row, col) with a prime.
88  void Prime(int row, int col) { marks_[row][col] = PRIME; }
89 
90  // Find a column in row containing a prime, or return
91  // kHungarianOptimizerColNotFound if no such column exists.
92  int FindPrimeInRow(int row) const;
93 
94  // Remove the prime marks_ from every cell in the matrix.
95  void ClearPrimes();
96 
97  // Does column col contain a star?
98  bool ColContainsStar(int col) const { return stars_in_col_[col] > 0; }
99 
100  // Is row 'row' covered?
101  bool RowCovered(int row) const { return rows_covered_[row]; }
102 
103  // Cover row 'row'.
104  void CoverRow(int row) { rows_covered_[row] = true; }
105 
106  // Uncover row 'row'.
107  void UncoverRow(int row) { rows_covered_[row] = false; }
108 
109  // Is column col covered?
110  bool ColCovered(int col) const { return cols_covered_[col]; }
111 
112  // Cover column col.
113  void CoverCol(int col) { cols_covered_[col] = true; }
114 
115  // Uncover column col.
116  void UncoverCol(int col) { cols_covered_[col] = false; }
117 
118  // Uncover ever row and column in the matrix.
119  void ClearCovers();
120 
121  // Find the smallest uncovered cell in the matrix.
122  double FindSmallestUncovered() const;
123 
124  // Find an uncovered zero and store its coordinates in (zeroRow_, zeroCol_)
125  // and return true, or return false if no such cell exists.
126  bool FindZero(int* zero_row, int* zero_col) const;
127 
128  // Print the matrix to stdout (for debugging.)
129  void PrintMatrix();
130 
131  // Run the Munkres algorithm!
132  void DoMunkres();
133 
134  // Step 1.
135  // For each row of the matrix, find the smallest element and subtract it
136  // from every element in its row. Go to Step 2.
137  void ReduceRows();
138 
139  // Step 2.
140  // Find a zero (Z) in the matrix. If there is no starred zero in its row
141  // or column, star Z. Repeat for every element in the matrix. Go to step 3.
142  // Note: profiling shows this method to use 9.2% of the CPU - the next
143  // slowest step takes 0.6%. I can't think of a way of speeding it up though.
144  void StarZeroes();
145 
146  // Step 3.
147  // Cover each column containing a starred zero. If all columns are
148  // covered, the starred zeros describe a complete set of unique assignments.
149  // In this case, terminate the algorithm. Otherwise, go to step 4.
150  void CoverStarredZeroes();
151 
152  // Step 4.
153  // Find a noncovered zero and prime it. If there is no starred zero in the
154  // row containing this primed zero, Go to Step 5. Otherwise, cover this row
155  // and uncover the column containing the starred zero. Continue in this manner
156  // until there are no uncovered zeros left, then go to Step 6.
157  void PrimeZeroes();
158 
159  // Step 5.
160  // Construct a series of alternating primed and starred zeros as follows.
161  // Let Z0 represent the uncovered primed zero found in Step 4. Let Z1 denote
162  // the starred zero in the column of Z0 (if any). Let Z2 denote the primed
163  // zero in the row of Z1 (there will always be one). Continue until the
164  // series terminates at a primed zero that has no starred zero in its column.
165  // Unstar each starred zero of the series, star each primed zero of the
166  // series, erase all primes and uncover every line in the matrix. Return to
167  // Step 3.
168  void MakeAugmentingPath();
169 
170  // Step 6.
171  // Add the smallest uncovered value in the matrix to every element of each
172  // covered row, and subtract it from every element of each uncovered column.
173  // Return to Step 4 without altering any stars, primes, or covered lines.
174  void AugmentPath();
175 
176  // The size of the problem, i.e. max(#agents, #tasks).
177  int matrix_size_;
178 
179  // The expanded cost matrix.
180  std::vector<std::vector<double>> costs_;
181 
182  // The greatest cost in the initial cost matrix.
183  double max_cost_;
184 
185  // Which rows and columns are currently covered.
186  std::vector<bool> rows_covered_;
187  std::vector<bool> cols_covered_;
188 
189  // The marks_ (star/prime/none) on each element of the cost matrix.
190  std::vector<std::vector<Mark>> marks_;
191 
192  // The number of stars in each column - used to speed up coverStarredZeroes.
193  std::vector<int> stars_in_col_;
194 
195  // Representation of a path_ through the matrix - used in step 5.
196  std::vector<int> preimage_; // i.e. the agents
197  std::vector<int> image_; // i.e. the tasks
198 
199  // The width_ and height_ of the initial (non-expanded) cost matrix.
200  int width_;
201  int height_;
202 
203  // The current state of the algorithm
204  HungarianOptimizer::Step state_;
205 };
206 
208  const std::vector<std::vector<double>>& costs)
209  : matrix_size_(0),
210  costs_(),
211  max_cost_(0),
212  rows_covered_(),
213  cols_covered_(),
214  marks_(),
215  stars_in_col_(),
216  preimage_(),
217  image_(),
218  width_(0),
219  height_(0),
220  state_(nullptr) {
221  width_ = costs.size();
222 
223  if (width_ > 0) {
224  height_ = costs[0].size();
225  } else {
226  height_ = 0;
227  }
228 
229  matrix_size_ = std::max(width_, height_);
230  max_cost_ = 0;
231 
232  // Generate the expanded cost matrix by adding extra 0-valued elements in
233  // order to make a square matrix. At the same time, find the greatest cost
234  // in the matrix (used later if we want to maximize rather than minimize the
235  // overall cost.)
236  costs_.resize(matrix_size_);
237  for (int row = 0; row < matrix_size_; ++row) {
238  costs_[row].resize(matrix_size_);
239  }
240 
241  for (int row = 0; row < matrix_size_; ++row) {
242  for (int col = 0; col < matrix_size_; ++col) {
243  if ((row >= width_) || (col >= height_)) {
244  costs_[row][col] = 0;
245  } else {
246  costs_[row][col] = costs[row][col];
247  max_cost_ = std::max(max_cost_, costs_[row][col]);
248  }
249  }
250  }
251 
252  // Initially, none of the cells of the matrix are marked.
253  marks_.resize(matrix_size_);
254  for (int row = 0; row < matrix_size_; ++row) {
255  marks_[row].resize(matrix_size_);
256  for (int col = 0; col < matrix_size_; ++col) {
257  marks_[row][col] = NONE;
258  }
259  }
260 
261  stars_in_col_.resize(matrix_size_);
262 
263  rows_covered_.resize(matrix_size_);
264  cols_covered_.resize(matrix_size_);
265 
266  preimage_.resize(matrix_size_ * 2);
267  image_.resize(matrix_size_ * 2);
268 }
269 
270 // Find an assignment which maximizes the total cost.
271 // Return an array of pairs of integers. Each pair (i, j) corresponds to
272 // assigning agent i to task j.
273 void HungarianOptimizer::Maximize(std::vector<int>* preimage,
274  std::vector<int>* image) {
275  // Find a maximal assignment by subtracting each of the
276  // original costs from max_cost_ and then minimizing.
277  for (int row = 0; row < width_; ++row) {
278  for (int col = 0; col < height_; ++col) {
279  costs_[row][col] = max_cost_ - costs_[row][col];
280  }
281  }
282  Minimize(preimage, image);
283 }
284 
285 // Find an assignment which minimizes the total cost.
286 // Return an array of pairs of integers. Each pair (i, j) corresponds to
287 // assigning agent i to task j.
288 void HungarianOptimizer::Minimize(std::vector<int>* preimage,
289  std::vector<int>* image) {
290  DoMunkres();
291  FindAssignments(preimage, image);
292 }
293 
294 // Convert the final cost matrix into a set of assignments of agents -> tasks.
295 // Return an array of pairs of integers, the same as the return values of
296 // Minimize() and Maximize()
297 void HungarianOptimizer::FindAssignments(std::vector<int>* preimage,
298  std::vector<int>* image) {
299  preimage->clear();
300  image->clear();
301  for (int row = 0; row < width_; ++row) {
302  for (int col = 0; col < height_; ++col) {
303  if (IsStarred(row, col)) {
304  preimage->push_back(row);
305  image->push_back(col);
306  break;
307  }
308  }
309  }
310  // TODO(user)
311  // result_size = min(width_, height_);
312  // CHECK image.size() == result_size
313  // CHECK preimage.size() == result_size
314 }
315 
316 // Find a column in row 'row' containing a star, or return
317 // kHungarianOptimizerColNotFound if no such column exists.
318 int HungarianOptimizer::FindStarInRow(int row) const {
319  for (int col = 0; col < matrix_size_; ++col) {
320  if (IsStarred(row, col)) {
321  return col;
322  }
323  }
324 
325  return kHungarianOptimizerColNotFound;
326 }
327 
328 // Find a row in column 'col' containing a star, or return
329 // kHungarianOptimizerRowNotFound if no such row exists.
330 int HungarianOptimizer::FindStarInCol(int col) const {
331  if (!ColContainsStar(col)) {
332  return kHungarianOptimizerRowNotFound;
333  }
334 
335  for (int row = 0; row < matrix_size_; ++row) {
336  if (IsStarred(row, col)) {
337  return row;
338  }
339  }
340 
341  // NOTREACHED
342  return kHungarianOptimizerRowNotFound;
343 }
344 
345 // Find a column in row containing a prime, or return
346 // kHungarianOptimizerColNotFound if no such column exists.
347 int HungarianOptimizer::FindPrimeInRow(int row) const {
348  for (int col = 0; col < matrix_size_; ++col) {
349  if (IsPrimed(row, col)) {
350  return col;
351  }
352  }
353 
354  return kHungarianOptimizerColNotFound;
355 }
356 
357 // Remove the prime marks from every cell in the matrix.
358 void HungarianOptimizer::ClearPrimes() {
359  for (int row = 0; row < matrix_size_; ++row) {
360  for (int col = 0; col < matrix_size_; ++col) {
361  if (IsPrimed(row, col)) {
362  marks_[row][col] = NONE;
363  }
364  }
365  }
366 }
367 
368 // Uncovery ever row and column in the matrix.
369 void HungarianOptimizer::ClearCovers() {
370  for (int x = 0; x < matrix_size_; x++) {
371  UncoverRow(x);
372  UncoverCol(x);
373  }
374 }
375 
376 // Find the smallest uncovered cell in the matrix.
377 double HungarianOptimizer::FindSmallestUncovered() const {
378  double minval = std::numeric_limits<double>::max();
379 
380  for (int row = 0; row < matrix_size_; ++row) {
381  if (RowCovered(row)) {
382  continue;
383  }
384 
385  for (int col = 0; col < matrix_size_; ++col) {
386  if (ColCovered(col)) {
387  continue;
388  }
389 
390  minval = std::min(minval, costs_[row][col]);
391  }
392  }
393 
394  return minval;
395 }
396 
397 // Find an uncovered zero and store its co-ordinates in (zeroRow, zeroCol)
398 // and return true, or return false if no such cell exists.
399 bool HungarianOptimizer::FindZero(int* zero_row, int* zero_col) const {
400  for (int row = 0; row < matrix_size_; ++row) {
401  if (RowCovered(row)) {
402  continue;
403  }
404 
405  for (int col = 0; col < matrix_size_; ++col) {
406  if (ColCovered(col)) {
407  continue;
408  }
409 
410  if (costs_[row][col] == 0) {
411  *zero_row = row;
412  *zero_col = col;
413  return true;
414  }
415  }
416  }
417 
418  return false;
419 }
420 
421 // Print the matrix to stdout (for debugging.)
422 void HungarianOptimizer::PrintMatrix() {
423  for (int row = 0; row < matrix_size_; ++row) {
424  for (int col = 0; col < matrix_size_; ++col) {
425  absl::PrintF("%g ", costs_[row][col]);
426 
427  if (IsStarred(row, col)) {
428  absl::PrintF("*");
429  }
430 
431  if (IsPrimed(row, col)) {
432  absl::PrintF("'");
433  }
434  }
435  absl::PrintF("\n");
436  }
437 }
438 
439 // Run the Munkres algorithm!
440 void HungarianOptimizer::DoMunkres() {
441  state_ = &HungarianOptimizer::ReduceRows;
442  while (state_ != nullptr) {
443  (this->*state_)();
444  }
445 }
446 
447 // Step 1.
448 // For each row of the matrix, find the smallest element and subtract it
449 // from every element in its row. Go to Step 2.
450 void HungarianOptimizer::ReduceRows() {
451  for (int row = 0; row < matrix_size_; ++row) {
452  double min_cost = costs_[row][0];
453  for (int col = 1; col < matrix_size_; ++col) {
454  min_cost = std::min(min_cost, costs_[row][col]);
455  }
456  for (int col = 0; col < matrix_size_; ++col) {
457  costs_[row][col] -= min_cost;
458  }
459  }
460  state_ = &HungarianOptimizer::StarZeroes;
461 }
462 
463 // Step 2.
464 // Find a zero (Z) in the matrix. If there is no starred zero in its row
465 // or column, star Z. Repeat for every element in the matrix. Go to step 3.
466 // of the CPU - the next slowest step takes 0.6%. I can't think of a way
467 // of speeding it up though.
468 void HungarianOptimizer::StarZeroes() {
469  // Since no rows or columns are covered on entry to this step, we use the
470  // covers as a quick way of marking which rows & columns have stars in them.
471  for (int row = 0; row < matrix_size_; ++row) {
472  if (RowCovered(row)) {
473  continue;
474  }
475 
476  for (int col = 0; col < matrix_size_; ++col) {
477  if (ColCovered(col)) {
478  continue;
479  }
480 
481  if (costs_[row][col] == 0) {
482  Star(row, col);
483  CoverRow(row);
484  CoverCol(col);
485  break;
486  }
487  }
488  }
489 
490  ClearCovers();
491  state_ = &HungarianOptimizer::CoverStarredZeroes;
492 }
493 
494 // Step 3.
495 // Cover each column containing a starred zero. If all columns are
496 // covered, the starred zeros describe a complete set of unique assignments.
497 // In this case, terminate the algorithm. Otherwise, go to step 4.
498 void HungarianOptimizer::CoverStarredZeroes() {
499  int num_covered = 0;
500 
501  for (int col = 0; col < matrix_size_; ++col) {
502  if (ColContainsStar(col)) {
503  CoverCol(col);
504  num_covered++;
505  }
506  }
507 
508  if (num_covered >= matrix_size_) {
509  state_ = nullptr;
510  return;
511  }
512  state_ = &HungarianOptimizer::PrimeZeroes;
513 }
514 
515 // Step 4.
516 // Find a noncovered zero and prime it. If there is no starred zero in the
517 // row containing this primed zero, Go to Step 5. Otherwise, cover this row
518 // and uncover the column containing the starred zero. Continue in this manner
519 // until there are no uncovered zeros left, then go to Step 6.
520 
521 void HungarianOptimizer::PrimeZeroes() {
522  // This loop is guaranteed to terminate in at most matrix_size_ iterations,
523  // as findZero() returns a location only if there is at least one uncovered
524  // zero in the matrix. Each iteration, either one row is covered or the
525  // loop terminates. Since there are matrix_size_ rows, after that many
526  // iterations there are no uncovered cells and hence no uncovered zeroes,
527  // so the loop terminates.
528  for (;;) {
529  int zero_row, zero_col;
530  if (!FindZero(&zero_row, &zero_col)) {
531  // No uncovered zeroes.
532  state_ = &HungarianOptimizer::AugmentPath;
533  return;
534  }
535 
536  Prime(zero_row, zero_col);
537  int star_col = FindStarInRow(zero_row);
538 
539  if (star_col != kHungarianOptimizerColNotFound) {
540  CoverRow(zero_row);
541  UncoverCol(star_col);
542  } else {
543  preimage_[0] = zero_row;
544  image_[0] = zero_col;
545  state_ = &HungarianOptimizer::MakeAugmentingPath;
546  return;
547  }
548  }
549 }
550 
551 // Step 5.
552 // Construct a series of alternating primed and starred zeros as follows.
553 // Let Z0 represent the uncovered primed zero found in Step 4. Let Z1 denote
554 // the starred zero in the column of Z0 (if any). Let Z2 denote the primed
555 // zero in the row of Z1 (there will always be one). Continue until the
556 // series terminates at a primed zero that has no starred zero in its column.
557 // Unstar each starred zero of the series, star each primed zero of the
558 // series, erase all primes and uncover every line in the matrix. Return to
559 // Step 3.
560 void HungarianOptimizer::MakeAugmentingPath() {
561  bool done = false;
562  int count = 0;
563 
564  // Note: this loop is guaranteed to terminate within matrix_size_ iterations
565  // because:
566  // 1) on entry to this step, there is at least 1 column with no starred zero
567  // (otherwise we would have terminated the algorithm already.)
568  // 2) each row containing a star also contains exactly one primed zero.
569  // 4) each column contains at most one starred zero.
570  //
571  // Since the path_ we construct visits primed and starred zeroes alternately,
572  // and terminates if we reach a primed zero in a column with no star, our
573  // path_ must either contain matrix_size_ or fewer stars (in which case the
574  // loop iterates fewer than matrix_size_ times), or it contains more. In
575  // that case, because (1) implies that there are fewer than
576  // matrix_size_ stars, we must have visited at least one star more than once.
577  // Consider the first such star that we visit more than once; it must have
578  // been reached immediately after visiting a prime in the same row. By (2),
579  // this prime is unique and so must have also been visited more than once.
580  // Therefore, that prime must be in the same column as a star that has been
581  // visited more than once, contradicting the assumption that we chose the
582  // first multiply visited star, or it must be in the same column as more
583  // than one star, contradicting (3). Therefore, we never visit any star
584  // more than once and the loop terminates within matrix_size_ iterations.
585 
586  while (!done) {
587  // First construct the alternating path...
588  int row = FindStarInCol(image_[count]);
589 
590  if (row != kHungarianOptimizerRowNotFound) {
591  count++;
592  preimage_[count] = row;
593  image_[count] = image_[count - 1];
594  } else {
595  done = true;
596  }
597 
598  if (!done) {
599  int col = FindPrimeInRow(preimage_[count]);
600  count++;
601  preimage_[count] = preimage_[count - 1];
602  image_[count] = col;
603  }
604  }
605 
606  // Then modify it.
607  for (int i = 0; i <= count; ++i) {
608  int row = preimage_[i];
609  int col = image_[i];
610 
611  if (IsStarred(row, col)) {
612  UnStar(row, col);
613  } else {
614  Star(row, col);
615  }
616  }
617 
618  ClearCovers();
619  ClearPrimes();
620  state_ = &HungarianOptimizer::CoverStarredZeroes;
621 }
622 
623 // Step 6
624 // Add the smallest uncovered value in the matrix to every element of each
625 // covered row, and subtract it from every element of each uncovered column.
626 // Return to Step 4 without altering any stars, primes, or covered lines.
627 void HungarianOptimizer::AugmentPath() {
628  double minval = FindSmallestUncovered();
629 
630  for (int row = 0; row < matrix_size_; ++row) {
631  for (int col = 0; col < matrix_size_; ++col) {
632  if (RowCovered(row)) {
633  costs_[row][col] += minval;
634  }
635 
636  if (!ColCovered(col)) {
637  costs_[row][col] -= minval;
638  }
639  }
640  }
641 
642  state_ = &HungarianOptimizer::PrimeZeroes;
643 }
644 
645 bool InputContainsNan(const std::vector<std::vector<double>>& input) {
646  for (const auto& subvector : input) {
647  for (const auto& num : subvector) {
648  if (std::isnan(num)) {
649  LOG(ERROR) << "The provided input contains " << num << ".";
650  return true;
651  }
652  }
653  }
654  return false;
655 }
656 
658  const std::vector<std::vector<double>>& cost,
659  absl::flat_hash_map<int, int>* direct_assignment,
660  absl::flat_hash_map<int, int>* reverse_assignment) {
661  if (InputContainsNan(cost)) {
662  LOG(ERROR) << "Returning before invoking the Hungarian optimizer.";
663  return;
664  }
665  std::vector<int> agent;
666  std::vector<int> task;
667  HungarianOptimizer hungarian_optimizer(cost);
668  hungarian_optimizer.Minimize(&agent, &task);
669  for (int i = 0; i < agent.size(); ++i) {
670  (*direct_assignment)[agent[i]] = task[i];
671  (*reverse_assignment)[task[i]] = agent[i];
672  }
673 }
674 
676  const std::vector<std::vector<double>>& cost,
677  absl::flat_hash_map<int, int>* direct_assignment,
678  absl::flat_hash_map<int, int>* reverse_assignment) {
679  if (InputContainsNan(cost)) {
680  LOG(ERROR) << "Returning before invoking the Hungarian optimizer.";
681  return;
682  }
683  std::vector<int> agent;
684  std::vector<int> task;
685  HungarianOptimizer hungarian_optimizer(cost);
686  hungarian_optimizer.Maximize(&agent, &task);
687  for (int i = 0; i < agent.size(); ++i) {
688  (*direct_assignment)[agent[i]] = task[i];
689  (*reverse_assignment)[task[i]] = agent[i];
690  }
691 }
692 
693 } // namespace operations_research
operations_research::HungarianOptimizer::Minimize
void Minimize(std::vector< int > *preimage, std::vector< int > *image)
Definition: hungarian.cc:288
min
int64 min
Definition: alldiff_cst.cc:138
max
int64 max
Definition: alldiff_cst.cc:139
LOG
#define LOG(severity)
Definition: base/logging.h:420
ERROR
const int ERROR
Definition: log_severity.h:32
operations_research::InputContainsNan
bool InputContainsNan(const std::vector< std::vector< double >> &input)
Definition: hungarian.cc:645
operations_research::HungarianOptimizer::Maximize
void Maximize(std::vector< int > *preimage, std::vector< int > *image)
Definition: hungarian.cc:273
operations_research::MaximizeLinearAssignment
void MaximizeLinearAssignment(const std::vector< std::vector< double >> &cost, absl::flat_hash_map< int, int > *direct_assignment, absl::flat_hash_map< int, int > *reverse_assignment)
Definition: hungarian.cc:675
logging.h
operations_research
The vehicle routing library lets one model and solve generic vehicle routing problems ranging from th...
Definition: dense_doubly_linked_list.h:21
cost
int64 cost
Definition: routing_flow.cc:130
hungarian.h
operations_research::HungarianOptimizer
Definition: hungarian.cc:28
col
ColIndex col
Definition: markowitz.cc:176
input
static int input(yyscan_t yyscanner)
row
RowIndex row
Definition: markowitz.cc:175
operations_research::MinimizeLinearAssignment
void MinimizeLinearAssignment(const std::vector< std::vector< double >> &cost, absl::flat_hash_map< int, int > *direct_assignment, absl::flat_hash_map< int, int > *reverse_assignment)
Definition: hungarian.cc:657
operations_research::HungarianOptimizer::HungarianOptimizer
HungarianOptimizer(const std::vector< std::vector< double >> &costs)
Definition: hungarian.cc:207