vnl_hungarian_algorithm.hxx
Go to the documentation of this file.
1 #ifndef vnl_hungarian_algorithm_hxx_
2 #define vnl_hungarian_algorithm_hxx_
3 
4 #include <vector>
5 #include <limits>
6 #include <algorithm>
7 #include <iostream>
9 
10 #include <vnl/vnl_matrix.h>
11 #ifdef _MSC_VER
12 # include <vcl_msvc_warnings.h>
13 #endif
14 #include <cassert>
15 
16 #ifdef DEBUG
17 #endif
18 
19 //-----------------------------------------------------------------------------
20 // Set Cost Matrix
21 //-----------------------------------------------------------------------------
22 template<class T>
23 void
25 SetCostMatrix( vnl_matrix<T> const& cost_in )
26 {
27  m_Cost_in = cost_in;
28  m_TotalCost = 0;
29 
30  // The Hungarian algorithm (seems to) only work for NxN cost
31  // matrices. We can solve the NxM case by padding the matrix with a
32  // constant cost.
33 
34  // Get Max size of the matrix
35  m_N = std::max( cost_in.rows(), cost_in.cols() );
36 
37  m_Cost.set_size( m_N, m_N);
38  m_Cost.fill( static_cast<T>(0) );
39 
40  // Initialize cost matrix
41  // Update the cost matrix ()
42  m_Cost.update( cost_in, 0, 0 );
43 }
44 
45 //-----------------------------------------------------------------------------
46 // Clear vector
47 //-----------------------------------------------------------------------------
48 template <class T>
49 void
51 clear_vector( std::vector<bool>& v )
52 {
53  typedef std::vector<bool>::iterator iter;
54  iter end = v.end();
55  for ( iter i = v.begin(); i != end; ++i )
56  {
57  *i = false;
58  }
59 }
60 
61 //-----------------------------------------------------------------------------
62 // Run Algorithm
63 //-----------------------------------------------------------------------------
64 template <class T>
65 void
68 {
69  // Step 0
70  // Make sure there are at least as many rows as columns
71  // [ This seems to be misleading since the algorithm presented here
72  // seems to only work for NxN matrices.]
73 
74  Step_0();
75 
76  // Step 1:
77  // For each row of the matrix, find the smallest element and subtract
78  // it from every element in its row. Go to Step 2.
79 
80  Step_1();
81 
82  // Step 2:
83  // Find a zero (Z) in the resulting matrix. If there is no starred
84  // zero in its row or column, star Z. Repeat for each element in the
85  // matrix. Go to Step 3.
86 
87  Step_2();
88 
89  STEP_TYPE step = STEP_3;
90 
91  while ( step != STEP_done )
92  {
93  switch ( step )
94  {
95  case STEP_3 :
96  // Step 3: Cover each column containing a starred zero. If K
97  // columns are covered, the starred zeros describe a complete set of
98  // unique assignments. In this case, Go to DONE, otherwise, Go to
99  // Step 4.
100  step = Step_3();
101  break;
102 
103  case STEP_4 :
104  // Step 4: Find a noncovered zero and prime it. If there is no
105  // starred zero in the row containing this primed zero, Go to Step
106  // 5. Otherwise, cover this row and uncover the column containing
107  // the starred zero. Continue in this manner until there are no
108  // uncovered zeros left. Save the smallest uncovered value and Go to
109  // Step 6.
110  step = Step_4();
111  break;
112 
113  case STEP_5 :
114  // Step 5: Construct a series of alternating primed and starred
115  // zeros as follows. Let Z0 represent the uncovered primed zero
116  // found in Step 4. Let Z1 denote the starred zero in the column of
117  // Z0 (if any). Let Z2 denote the primed zero in the row of Z1
118  // (there will always be one). Continue until the series terminates
119  // at a primed zero that has no starred zero in its column. Unstar
120  // each starred zero of the series, star each primed zero of the
121  // series, erase all primes and uncover every line in the matrix.
122  // Return to Step 3.
123  step = Step_5();
124  break;
125 
126  case STEP_6 :
127  // Step 6: Add the value found in Step 4 to every element of each
128  // covered row, and subtract it from every element of each uncovered
129  // column. Return to Step 4 without altering any stars, primes, or
130  // covered
131  step = Step_6();
132  break;
133 
134  default :
135  step = STEP_done;
136  break;
137  }
138  }
139 
140  // DONE: Assignment pairs are indicated by the positions of the
141  // starred zeros in the cost matrix. If C(i,j) is a starred zero,
142  // then the element associated with row i is assigned to the element
143  // associated with column j.
144 
145  Step_done();
146 }
147 
148 //-----------------------------------------------------------------------------
149 // Step 0
150 // Make sure there are at least as many rows as columns
151 // [ This seems to be misleading since the algorithm presented here
152 // seems to only work for NxN matrices.]
153 //-----------------------------------------------------------------------------
154 template <class T>
157 {
158  // M(i,j) = NORMAL => cost(i,j) is normal
159  // M(i,j) = STAR => cost(i,j) is starred
160  // M(i,j) = PRIME => cost(i,j) is primed
161 
162  m_M.set_size( m_N, m_N);
163  m_M.fill( NORMAL );
164 
165  // R_cov[i] = true => row i is covered
166  // C_cov[j] = true => column j is covered
167 
168  m_R_cov.assign(m_N, false);
169  m_C_cov.assign(m_N, false);
170  return STEP_1;
171 }
172 
173 //-----------------------------------------------------------------------------
174 // Step 1:
175 // For each row of the matrix, find the smallest element and subtract
176 // it from every element in its row. Go to Step 2.
177 //-----------------------------------------------------------------------------
178 template <class T>
181 {
182 //creer j a l'exterieur
183 
184  for ( unsigned i = 0; i < m_N; ++i )
185  {
186  T mn = m_Cost(i,0);
187  for ( unsigned j = 1; j < m_N; ++j )
188  {
189  if ( mn > m_Cost(i,j) )
190  {
191  mn = m_Cost(i,j);
192  }
193  }
194  for ( unsigned j = 0; j < m_N; ++j )
195  {
196  m_Cost(i,j) -= mn;
197  }
198  }
199  return STEP_2;
200 }
201 
202 
203 //-----------------------------------------------------------------------------
204 // Step 2:
205 // Find a zero (Z) in the resulting matrix. If there is no starred
206 // zero in its row or column, star Z. Repeat for each element in the
207 // matrix. Go to Step 3.
208 //-----------------------------------------------------------------------------
209 template <class T>
212 {
213  // We'll use C_cov and R_cov to indicate if there is a starred
214  // zero in that column or row, respectively
215  for ( unsigned i = 0; i < m_N; ++i )
216  {
217  if ( ! m_R_cov[i] )
218  {
219  for ( unsigned j = 0; j < m_N; ++j )
220  {
221  if ( m_Cost(i,j) == 0 && ! m_C_cov[j] )
222  {
223  m_M(i,j) = STAR; // star it
224  m_R_cov[i] = true; // and update the row & col status.
225  m_C_cov[j] = true;
226  break; // the row is now starred. Don't look at the rest.
227  }
228  }
229  }
230  }
231  clear_vector( m_R_cov );
232  clear_vector( m_C_cov );
233  return STEP_3;
234 }
235 
236 //-----------------------------------------------------------------------------
237 // Step 3: Cover each column containing a starred zero. If K
238 // columns are covered, the starred zeros describe a complete set of
239 // unique assignments. In this case, Go to DONE, otherwise, Go to
240 // Step 4.
241 //-----------------------------------------------------------------------------
242 template <class T>
245 {
246  unsigned count = 0;
247  for ( unsigned j = 0; j < m_N; ++j )
248  {
249  for ( unsigned i = 0; i < m_N; ++i )
250  {
251  if ( m_M(i,j) == STAR )
252  {
253  m_C_cov[j] = true;
254  ++count;
255  break; // to the next column
256  }
257  }
258  }
259 
260  if ( count == m_N )
261  {
262  return STEP_done;
263  }
264  else
265  {
266  return STEP_4;
267  }
268 }
269 
270 //-----------------------------------------------------------------------------
271 // Step 4: Find a noncovered zero and prime it. If there is no
272 // starred zero in the row containing this primed zero, Go to Step
273 // 5. Otherwise, cover this row and uncover the column containing
274 // the starred zero. Continue in this manner until there are no
275 // uncovered zeros left. Save the smallest uncovered value and Go to
276 // Step 6.
277 //-----------------------------------------------------------------------------
278 template <class T>
281 {
282  m_Z0_r = m_Z0_c = (unsigned int)(-1);
283  // Find an uncovered zero
284  // This loop will exit with a goto step_five or step_six.
285 
286  unsigned i, j; // row and column of the uncovered zero, if any.
287  for (i = 0 ; i < m_N; ++i )
288  {
289  if ( ! m_R_cov[i] )
290  {
291  for ( j = 0; j < m_N; ++j )
292  {
293 #ifdef DEBUG
294  std::cout << m_Cost(i,j) << std::endl;
295 #endif
296  if ( m_Cost(i,j) == 0 && ! m_C_cov[j] )
297  {
298  m_M(i,j) = PRIME; // prime it
299  bool star_in_row = false;
300  for ( unsigned j2 = 0; j2 < m_N; ++j2 )
301  {
302  if ( m_M(i,j2) == STAR )
303  {
304  star_in_row = true;
305  // cover the row, uncover the star column
306  m_R_cov[i] = true;
307  m_C_cov[j2] = false;
308  break; // out of searching for stars
309  }
310  }
311 
312  // If there isn't go to step 5
313  if ( ! star_in_row )
314  {
315  m_Z0_r = i;
316  m_Z0_c = j;
317  return STEP_5;
318  }
319  return STEP_4;
320  }
321  }
322  }
323  }
324 
325  // We should find the smallest uncovered value, but it's more
326  // convenient to find it when we get to step six. We only need
327  // it there anyway.
328  return STEP_6;
329 }
330 
331 //-----------------------------------------------------------------------------
332 // Step 5: Construct a series of alternating primed and starred
333 // zeros as follows. Let Z0 represent the uncovered primed zero
334 // found in Step 4. Let Z1 denote the starred zero in the column of
335 // Z0 (if any). Let Z2 denote the primed zero in the row of Z1
336 // (there will always be one). Continue until the series terminates
337 // at a primed zero that has no starred zero in its column. Unstar
338 // each starred zero of the series, star each primed zero of the
339 // series, erase all primes and uncover every line in the matrix.
340 // Return to Step 3.
341 //-----------------------------------------------------------------------------
342 template <class T>
345 {
346  unsigned i = m_Z0_r;
347  unsigned j = m_Z0_c;
348  std::vector<unsigned> rows, cols;
349 
350  while ( true )
351  {
352  // This is the primed zero
353  assert( m_M(i,j) == PRIME );
354  rows.push_back( i );
355  cols.push_back( j );
356 
357  // Look for a starred zero in this column
358  for ( i = 0; i < m_N; ++i )
359  {
360  if ( m_M(i,j) == STAR )
361  {
362  break;
363  }
364  }
365 
366  if ( i == m_N )
367  {
368  // we didn't find a starred zero. Stop the loop
369  break;
370  }
371 
372  // This is the starred zero
373  rows.push_back( i );
374  cols.push_back( j );
375 
376  // Look for the primed zero in the row of the starred zero
377  for ( j = 0; j < m_N; ++j )
378  {
379  if ( m_M(i,j) == PRIME )
380  {
381  break;
382  }
383  }
384  assert( j < m_N ); // there should always be one
385 
386  // go back to the top to mark the primed zero, and repeat.
387  }
388 
389  // Series has terminated. Unstar each star and star each prime in
390  // the series.
391  for ( unsigned idx = 0; idx < rows.size(); ++idx )
392  {
393  unsigned i = rows[idx];
394  unsigned j = cols[idx];
395  if ( m_M(i,j) == STAR )
396  {
397  m_M(i,j) = NORMAL; // unstar each starred zero
398  }
399  else
400  {
401  assert( m_M(i,j) == PRIME );
402  m_M(i,j) = STAR; // star each primed zero
403  }
404  }
405 
406  // Erase all primes.
407  for ( unsigned i = 0; i < m_N; ++i )
408  {
409  for ( unsigned j = 0; j < m_N; ++j )
410  {
411  if ( m_M(i,j) == PRIME )
412  {
413  m_M(i,j) = NORMAL;
414  }
415  }
416  }
417 
418  // Uncover everything
419  clear_vector( m_R_cov );
420  clear_vector( m_C_cov );
421 
422  return STEP_3;
423 }
424 
425 //-----------------------------------------------------------------------------
426 // Step 6: Add the value found in Step 4 to every element of each
427 // covered row, and subtract it from every element of each uncovered
428 // column. Return to Step 4 without altering any stars, primes, or
429 // covered lines.
430 //-----------------------------------------------------------------------------
431 template <class T>
434 {
435  // The value found in step 4 is the smallest uncovered value. Find it now.
436  T minval = std::numeric_limits<T>::max();
437  for ( unsigned i = 0; i < m_N; ++i )
438  {
439  if ( ! m_R_cov[i] )
440  {
441  for ( unsigned j = 0; j < m_N; ++j )
442  {
443  if ( ! m_C_cov[j] && m_Cost(i,j) < minval )
444  {
445  minval = m_Cost(i,j);
446  }
447  }
448  }
449  }
450 
451  // Modify the matrix as instructed.
452  for ( unsigned i = 0; i < m_N; ++i )
453  {
454  for ( unsigned j = 0; j < m_N; ++j )
455  {
456  if ( m_R_cov[i] )
457  {
458  m_Cost(i,j) += minval;
459  }
460  if ( ! m_C_cov[j] )
461  {
462  m_Cost(i,j) -= minval;
463  }
464  }
465  }
466 
467  return STEP_4;
468 }
469 
470 
471 //-----------------------------------------------------------------------------
472 // DONE: Assignment pairs are indicated by the positions of the
473 // starred zeros in the cost matrix. If C(i,j) is a starred zero,
474 // then the element associated with row i is assigned to the element
475 // associated with column j.
476 //-----------------------------------------------------------------------------
477 template <class T>
478 void
480 {
481  std::vector<unsigned> assign( m_Cost_in.rows(), (unsigned int)(-1) );
482  m_AssignmentVector = assign;
483 
484  // Find the stars and generate the resulting assignment. Only
485  // check the sub-matrix of cost that corresponds to the input cost
486  // matrix. The remaining rows and columns are unassigned.
487  for ( unsigned j = 0; j < m_Cost_in.cols(); ++j )
488  {
489  for ( unsigned i = 0; i < m_Cost_in.rows(); ++i )
490  {
491  if ( m_M(i,j) == STAR )
492  {
493  m_AssignmentVector[i] = j;
494  m_TotalCost += m_Cost_in[i][j];
495  }
496  }
497  }
498 }
499 
500 //-----------------------------------------------------------------------------
501 // Returns the total cost of the assignment
502 //-----------------------------------------------------------------------------
503 template <class T>
504 T
506 {
507  return m_TotalCost;
508 }
509 
510 //-----------------------------------------------------------------------------
511 // Returns the assignment matrix
512 //-----------------------------------------------------------------------------
513 template <class T>
516 {
517  return m_M;
518 }
519 
520 //-----------------------------------------------------------------------------
521 // Returns the assignment vector
522 //-----------------------------------------------------------------------------
523 template <class T>
526 {
527  return m_AssignmentVector;
528 }
529 
530 #undef VNL_HUNGARIAN_ALGORITHM_INSTANTIATE
531 #define VNL_HUNGARIAN_ALGORITHM_INSTANTIATE(T) \
532 template class VNL_EXPORT vnl_hungarian_algorithm<T >
533 
534 #endif // vnl_hungarian_algorithm_hxx_
unsigned int cols() const
Return the number of columns.
Definition: vnl_matrix.h:183
void Step_done()
Step done - Returns a vector containing the result of the assignment.
STEP_TYPE Step_4()
Step 4: Find a noncovered zero and prime it.
An ordinary mathematical matrix.
AssignmentVectorType GetAssignmentVector()
Returns the assignment vector.
T GetTotalCost()
Returns the total cost of the assignment.
STEP_TYPE Step_1()
Step 1 - For each row of the matrix, find the smallest element and subtract it from every element in ...
#define v
Definition: vnl_vector.h:42
STEP_TYPE Step_5()
Step 5 - Construct a series of alternating primed and starred zeros as follows.
STEP_TYPE Step_3()
Step 3 - Cover each column containing a starred zero.
An ordinary mathematical matrix.
Definition: vnl_adjugate.h:22
STEP_TYPE Step_0()
Step 0 - Make sure there are at least as many rows as columns in the cost matrix.
vnl_decnum max(vnl_decnum const &x, vnl_decnum const &y)
Definition: vnl_decnum.h:412
void StartAssignment()
Starts the assignment.
AssignmentMatrixType GetAssignmentMatrix()
Returns the assignment matrix.
std::vector< unsigned > AssignmentVectorType
void SetCostMatrix(vnl_matrix< T > const &)
Starts the assignment.
unsigned int rows() const
Return the number of rows.
Definition: vnl_matrix.h:179
STEP_TYPE Step_2()
Step 2 - Find a zero (Z) in the resulting matrix.
void clear_vector(std::vector< bool > &)
Sets all the values in the input bool vector to false.