vnl_hungarian_algorithm.h
Go to the documentation of this file.
1 #ifndef vnl_hungarian_algorithm_h_
2 #define vnl_hungarian_algorithm_h_
3 //:
4 // \file
5 // \author Amitha Perera
6 // \date Sep 2004
7 // Refactored by Nicolas Rannou (Harvard), Oct 2010, such that the algorithm
8 // presents itself in a templated and more object-oriented manner.
9 
10 #include <vector>
11 #ifdef _MSC_VER
12 # include <vcl_msvc_warnings.h>
13 #endif
14 #include <vnl/vnl_matrix.h>
15 #include "vnl/vnl_export.h"
16 
17 //: Find the best column to row assignment given a cost matrix.
18 //
19 // This is an implementation of the Hungarian algorithm (also known
20 // as the Munkres algorithm). It finds the minimum cost assignment of
21 // the rows of the cost matrix \a cost (workers) to the columns
22 // (jobs).
23 //
24 // \param cost An N x M cost matrix. The costs cannot be -Infinity.
25 //
26 // \returns A vector v of size N such that v[i] = j means that row i
27 // should be assigned to column j. \code v[i] = -1u \endcode (= \code
28 // unsigned(-1) \endcode ) means that row i was not assigned to any
29 // column. If N > M, then every column will be assigned to some
30 // row. If N < M then every row will be assigned to some column.
31 //
32 // \relatesalso vnl_matrix
33 template <class T>
34 class VNL_EXPORT vnl_hungarian_algorithm
35 {
36  public:
37 
38  // The steps of the algorithm described below are taken from
39  // http://www.cs.duke.edu/brd/Teaching/Bio/asmb/current/Handouts/munkres.html
40  enum STEP_TYPE {
41  STEP_0 = 0,
48  STEP_done
49  };
50 
51  enum STATE_TYPE {
52  NORMAL=0,
54  PRIME
55  };
56 
58  typedef std::vector<unsigned> AssignmentVectorType;
59 
60  vnl_hungarian_algorithm() : m_TotalCost(0) {}
61 
62  ~vnl_hungarian_algorithm() = default;
63 
64  //: This constructor (and the following cast operator) is provided for backward compatibility with the original function implementation
65  vnl_hungarian_algorithm(vnl_matrix<T> const& cost) { SetCostMatrix(cost); StartAssignment(); }
66  operator std::vector<unsigned>() { return GetAssignmentVector(); }
67 
68  //: Starts the assignment
69  void SetCostMatrix( vnl_matrix< T > const& );
70 
71  //: Starts the assignment
72  void StartAssignment();
73 
74  //: Returns the total cost of the assignment
75  T GetTotalCost();
76 
77  //: Returns the assignment matrix
78  AssignmentMatrixType GetAssignmentMatrix();
79 
80  //: Returns the assignment vector
81  AssignmentVectorType GetAssignmentVector();
82 
83  protected:
84  //: Step 0 - Make sure there are at least as many rows as columns in the cost matrix
85  // The nxm cost matrix is a matrix in which each element represents
86  // the cost of assigning one of n workers to one of m jobs.
87  // \returns the next step to go to (which is Step 1).
88  STEP_TYPE Step_0();
89 
90  //: Step 1 - For each row of the matrix, find the smallest element and subtract it from every element in its row.
91  // \returns the next step to go to (which is Step 2).
92  STEP_TYPE Step_1();
93 
94  //: Step 2 - Find a zero (Z) in the resulting matrix.
95  // If there is no starred zero in its row or column, star Z.
96  // Repeat for each element in the matrix.
97  // \returns the next step to go to (which is Step 3)
98  STEP_TYPE Step_2();
99 
100  //: Step 3 - Cover each column containing a starred zero.
101  // If K columns are covered, the starred zeros describe a complete
102  // set of unique assignments.
103  // In this case, Go to DONE, otherwise, Go to Step 4.
104  // \returns the next step to go to
105  STEP_TYPE Step_3();
106 
107  //: Step 4: Find a noncovered zero and prime it.
108  // If there is no starred zero in the row containing this primed zero, Go to Step 5.
109  // Otherwise, cover this row and uncover the column containing the starred
110  // zero. Continue in this manner until there are no uncovered zeros left.
111  // Save the smallest uncovered value and Go to Step 6.
112  // \returns the next step to go to
113  STEP_TYPE Step_4();
114 
115  //: Step 5 - Construct a series of alternating primed and starred zeros as follows.
116  // Let Z0 represent the uncovered primed zero found in Step 4.
117  // Let Z1 denote the starred zero in the column of Z0 (if any).
118  // Let Z2 denote the primed zero in the row of Z1 (there will always be
119  // one). Continue until the series terminates at a primed zero that has
120  // no starred zero in its column. Unstar each starred zero of the series,
121  // star each primed zero of the series, erase all primes and uncover every
122  // line in the matrix. Return to Step 3.
123  // \returns the next step to go to
124  STEP_TYPE Step_5();
125 
126  //: Step 6 -
127  // Add the value found in Step 4 to every element of each covered row,
128  // and subtract it from every element of each uncovered column.
129  // Return to Step 4 without altering any stars, primes, or covered lines.
130  // \returns the next step to go to
131  STEP_TYPE Step_6();
132 
133  //: Step done - Returns a vector containing the result of the assignment.
134  // Assignment pairs are indicated by the positions of the
135  // starred zeros in the cost matrix. If C(i,j) is a starred zero,
136  // then the element associated with row i is assigned to the element
137  // associated with column j.
138  void Step_done();
139 
140  //: Sets all the values in the input bool vector to false.
141  void clear_vector( std::vector<bool>& );
142 
145 
146  //: Size of the input matrix
147  unsigned m_N;
148 
149  //: Row and col of the primed zero in step four to pass to step five.
150  unsigned m_Z0_r, m_Z0_c;
151 
152  //:
153  // m_M(i,j) = 1 => m_Cost(i,j) is starred
154  // m_M(i,j) = 2 => m_Cost(i,j) is primed
156 
157  //: m_R_cov[i] = true => row i is covered
158  std::vector<bool> m_R_cov;
159 
160  //: m_C_cov[j] = true => column j is covered
161  std::vector<bool> m_C_cov;
162 
163  //: Total cost of the assignment
165 
166  //: m_C_cov[j] = true => column j is covered
168 };
169 
170 #define VNL_HUNGARIAN_ALGORITHM_INSTANTIATE(T) extern "please #include vnl/vnl_hungarian_algorithm.hxx instead"
171 
172 #endif // vnl_hungarian_algorithm_h_
unsigned m_Z0_r
Row and col of the primed zero in step four to pass to step five.
An ordinary mathematical matrix.
vnl_hungarian_algorithm(vnl_matrix< T > const &cost)
This constructor (and the following cast operator) is provided for backward compatibility with the or...
AssignmentMatrixType m_M
m_M(i,j) = 1 => m_Cost(i,j) is starred m_M(i,j) = 2 => m_Cost(i,j) is primed
T m_TotalCost
Total cost of the assignment.
vnl_matrix< int > AssignmentMatrixType
AssignmentVectorType m_AssignmentVector
m_C_cov[j] = true => column j is covered.
std::vector< bool > m_R_cov
m_R_cov[i] = true => row i is covered.
unsigned m_N
Size of the input matrix.
std::vector< unsigned > AssignmentVectorType
Find the best column to row assignment given a cost matrix.
std::vector< bool > m_C_cov
m_C_cov[j] = true => column j is covered.