core/vnl/vnl_hungarian_algorithm.txx
Go to the documentation of this file.
00001 #ifndef vnl_hungarian_algorithm_txx_
00002 #define vnl_hungarian_algorithm_txx_
00003 
00004 #include "vnl_hungarian_algorithm.h"
00005 
00006 #include <vnl/vnl_matrix.h>
00007 #include <vcl_vector.h>
00008 #include <vcl_limits.h>
00009 #include <vcl_algorithm.h>
00010 #include <vcl_cassert.h>
00011 
00012 #ifdef DEBUG
00013 #include <vcl_iostream.h>
00014 #endif
00015 
00016 //-----------------------------------------------------------------------------
00017 // Set Cost Matrix
00018 //-----------------------------------------------------------------------------
00019 template<class T>
00020 void
00021 vnl_hungarian_algorithm<T>::
00022 SetCostMatrix( vnl_matrix<T> const& cost_in )
00023 {
00024   m_Cost_in = cost_in;
00025   m_TotalCost = 0;
00026 
00027   // The Hungarian algorithm (seems to) only work for NxN cost
00028   // matrices. We can solve the NxM case by padding the matrix with a
00029   // constant cost.
00030 
00031   // Get Max size of the matrix
00032   m_N = vcl_max( cost_in.rows(), cost_in.cols() );
00033 
00034   m_Cost.set_size( m_N, m_N);
00035   m_Cost.fill( static_cast<T>(0) );
00036 
00037   // Initialize cost matrix
00038   // Update the cost matrix ()
00039   m_Cost.update( cost_in, 0, 0 );
00040 }
00041 
00042 //-----------------------------------------------------------------------------
00043 // Clear vector
00044 //-----------------------------------------------------------------------------
00045 template <class T>
00046 void
00047 vnl_hungarian_algorithm<T>::
00048 clear_vector( vcl_vector<bool>& v )
00049 {
00050   typedef vcl_vector<bool>::iterator iter;
00051   iter end = v.end();
00052   for ( iter i = v.begin(); i != end; ++i )
00053   {
00054     *i = false;
00055   }
00056 }
00057 
00058 //-----------------------------------------------------------------------------
00059 // Run Algorithm
00060 //-----------------------------------------------------------------------------
00061 template <class T>
00062 void
00063 vnl_hungarian_algorithm<T>::
00064 StartAssignment()
00065 {
00066   // Step 0
00067   // Make sure there are at least as many rows as columns
00068   // [ This seems to be misleading since the algorithm presented here
00069   // seems to only work for NxN matrices.]
00070 
00071   Step_0();
00072 
00073   // Step 1:
00074   // For each row of the matrix, find the smallest element and subtract
00075   // it from every element in its row.  Go to Step 2.
00076 
00077   Step_1();
00078 
00079   // Step 2:
00080   // Find a zero (Z) in the resulting matrix.  If there is no starred
00081   // zero in its row or column, star Z. Repeat for each element in the
00082   // matrix. Go to Step 3.
00083 
00084   Step_2();
00085 
00086   STEP_TYPE step = STEP_3;
00087 
00088   while ( step != STEP_done )
00089   {
00090     switch ( step )
00091     {
00092       case STEP_3 :
00093       // Step 3: Cover each column containing a starred zero.  If K
00094       // columns are covered, the starred zeros describe a complete set of
00095       // unique assignments.  In this case, Go to DONE, otherwise, Go to
00096       // Step 4.
00097         step = Step_3();
00098         break;
00099 
00100       case STEP_4 :
00101       // Step 4: Find a noncovered zero and prime it.  If there is no
00102       // starred zero in the row containing this primed zero, Go to Step
00103       // 5.  Otherwise, cover this row and uncover the column containing
00104       // the starred zero. Continue in this manner until there are no
00105       // uncovered zeros left. Save the smallest uncovered value and Go to
00106       // Step 6.
00107         step = Step_4();
00108         break;
00109 
00110       case STEP_5 :
00111       // Step 5: Construct a series of alternating primed and starred
00112       // zeros as follows.  Let Z0 represent the uncovered primed zero
00113       // found in Step 4.  Let Z1 denote the starred zero in the column of
00114       // Z0 (if any). Let Z2 denote the primed zero in the row of Z1
00115       // (there will always be one).  Continue until the series terminates
00116       // at a primed zero that has no starred zero in its column.  Unstar
00117       // each starred zero of the series, star each primed zero of the
00118       // series, erase all primes and uncover every line in the matrix.
00119       // Return to Step 3.
00120         step = Step_5();
00121         break;
00122 
00123       case STEP_6 :
00124       // Step 6: Add the value found in Step 4 to every element of each
00125       // covered row, and subtract it from every element of each uncovered
00126       // column.  Return to Step 4 without altering any stars, primes, or
00127       // covered
00128         step = Step_6();
00129         break;
00130 
00131       default :
00132         step = STEP_done;
00133         break;
00134     }
00135   }
00136 
00137   // DONE: Assignment pairs are indicated by the positions of the
00138   // starred zeros in the cost matrix.  If C(i,j) is a starred zero,
00139   // then the element associated with row i is assigned to the element
00140   // associated with column j.
00141 
00142   Step_done();
00143 }
00144 
00145 //-----------------------------------------------------------------------------
00146 // Step 0
00147 // Make sure there are at least as many rows as columns
00148 // [ This seems to be misleading since the algorithm presented here
00149 // seems to only work for NxN matrices.]
00150 //-----------------------------------------------------------------------------
00151 template <class T>
00152 typename vnl_hungarian_algorithm<T>::STEP_TYPE
00153 vnl_hungarian_algorithm<T>::Step_0()
00154 {
00155   // M(i,j) = NORMAL   =>  cost(i,j) is normal
00156   // M(i,j) = STAR     =>  cost(i,j) is starred
00157   // M(i,j) = PRIME    =>  cost(i,j) is primed
00158 
00159   m_M.set_size( m_N, m_N);
00160   m_M.fill( NORMAL );
00161 
00162   // R_cov[i] = true  => row i is covered
00163   // C_cov[j] = true  => column j is covered
00164 
00165   m_R_cov.assign(m_N, false);
00166   m_C_cov.assign(m_N, false);
00167   return STEP_1;
00168 }
00169 
00170 //-----------------------------------------------------------------------------
00171 // Step 1:
00172 // For each row of the matrix, find the smallest element and subtract
00173 // it from every element in its row.  Go to Step 2.
00174 //-----------------------------------------------------------------------------
00175 template <class T>
00176 typename vnl_hungarian_algorithm<T>::STEP_TYPE
00177 vnl_hungarian_algorithm<T>::Step_1()
00178 {
00179 //creer j a l'exterieur
00180 
00181   for ( unsigned i = 0; i < m_N; ++i )
00182   {
00183     T mn = m_Cost(i,0);
00184     for ( unsigned j = 1; j < m_N; ++j )
00185     {
00186       if ( mn > m_Cost(i,j) )
00187       {
00188         mn = m_Cost(i,j);
00189       }
00190     }
00191     for ( unsigned j = 0; j < m_N; ++j )
00192     {
00193       m_Cost(i,j) -= mn;
00194     }
00195   }
00196   return STEP_2;
00197 }
00198 
00199 
00200 //-----------------------------------------------------------------------------
00201 // Step 2:
00202 // Find a zero (Z) in the resulting matrix.  If there is no starred
00203 // zero in its row or column, star Z. Repeat for each element in the
00204 // matrix. Go to Step 3.
00205 //-----------------------------------------------------------------------------
00206 template <class T>
00207 typename vnl_hungarian_algorithm<T>::STEP_TYPE
00208 vnl_hungarian_algorithm<T>::Step_2()
00209 {
00210   // We'll use C_cov and R_cov to indicate if there is a starred
00211   // zero in that column or row, respectively
00212   for ( unsigned i = 0; i < m_N; ++i )
00213   {
00214     if ( ! m_R_cov[i] )
00215     {
00216       for ( unsigned j = 0; j < m_N; ++j )
00217       {
00218         if ( m_Cost(i,j) == 0 && ! m_C_cov[j] )
00219         {
00220           m_M(i,j) = STAR; // star it
00221           m_R_cov[i] = true; // and update the row & col status.
00222           m_C_cov[j] = true;
00223           break; // the row is now starred. Don't look at the rest.
00224         }
00225       }
00226     }
00227   }
00228   clear_vector( m_R_cov );
00229   clear_vector( m_C_cov );
00230   return STEP_3;
00231 }
00232 
00233 //-----------------------------------------------------------------------------
00234 // Step 3: Cover each column containing a starred zero.  If K
00235 // columns are covered, the starred zeros describe a complete set of
00236 // unique assignments.  In this case, Go to DONE, otherwise, Go to
00237 // Step 4.
00238 //-----------------------------------------------------------------------------
00239 template <class T>
00240 typename vnl_hungarian_algorithm<T>::STEP_TYPE
00241 vnl_hungarian_algorithm<T>::Step_3()
00242 {
00243   unsigned count = 0;
00244   for ( unsigned j = 0; j < m_N; ++j )
00245   {
00246     for ( unsigned i = 0; i < m_N; ++i )
00247     {
00248       if ( m_M(i,j) == STAR )
00249       {
00250         m_C_cov[j] = true;
00251         ++count;
00252         break; // to the next column
00253       }
00254     }
00255   }
00256 
00257   if ( count == m_N )
00258   {
00259     return STEP_done;
00260   }
00261   else
00262   {
00263     return STEP_4;
00264   }
00265 }
00266 
00267 //-----------------------------------------------------------------------------
00268 // Step 4: Find a noncovered zero and prime it.  If there is no
00269 // starred zero in the row containing this primed zero, Go to Step
00270 // 5.  Otherwise, cover this row and uncover the column containing
00271 // the starred zero. Continue in this manner until there are no
00272 // uncovered zeros left. Save the smallest uncovered value and Go to
00273 // Step 6.
00274 //-----------------------------------------------------------------------------
00275 template <class T>
00276 typename vnl_hungarian_algorithm<T>::STEP_TYPE
00277 vnl_hungarian_algorithm<T>::Step_4()
00278 {
00279   m_Z0_r = m_Z0_c = (unsigned int)(-1);
00280   // Find an uncovered zero
00281   // This loop will exit with a goto step_five or step_six.
00282 
00283     unsigned i, j; // row and column of the uncovered zero, if any.
00284     for (i = 0 ; i < m_N; ++i )
00285     {
00286       if ( ! m_R_cov[i] )
00287       {
00288         for ( j = 0; j < m_N; ++j )
00289         {
00290 #ifdef DEBUG
00291           vcl_cout << m_Cost(i,j) << vcl_endl;
00292 #endif
00293           if ( m_Cost(i,j) == 0 && ! m_C_cov[j] )
00294           {
00295             m_M(i,j) = PRIME; // prime it
00296             bool star_in_row = false;
00297             for ( unsigned j2 = 0; j2 < m_N; ++j2 )
00298             {
00299               if ( m_M(i,j2) == STAR )
00300               {
00301               star_in_row = true;
00302               // cover the row, uncover the star column
00303               m_R_cov[i] = true;
00304               m_C_cov[j2] = false;
00305               break; // out of searching for stars
00306             }
00307           }
00308 
00309           // If there isn't go to step 5
00310           if ( ! star_in_row )
00311           {
00312             m_Z0_r = i;
00313             m_Z0_c = j;
00314             return STEP_5;
00315           }
00316           return STEP_4;
00317         }
00318       }
00319     }
00320   }
00321 
00322   // We should find the smallest uncovered value, but it's more
00323   // convenient to find it when we get to step six. We only need
00324   // it there anyway.
00325   return STEP_6;
00326 }
00327 
00328 //-----------------------------------------------------------------------------
00329 // Step 5: Construct a series of alternating primed and starred
00330 // zeros as follows.  Let Z0 represent the uncovered primed zero
00331 // found in Step 4.  Let Z1 denote the starred zero in the column of
00332 // Z0 (if any). Let Z2 denote the primed zero in the row of Z1
00333 // (there will always be one).  Continue until the series terminates
00334 // at a primed zero that has no starred zero in its column.  Unstar
00335 // each starred zero of the series, star each primed zero of the
00336 // series, erase all primes and uncover every line in the matrix.
00337 // Return to Step 3.
00338 //-----------------------------------------------------------------------------
00339 template <class T>
00340 typename vnl_hungarian_algorithm<T>::STEP_TYPE
00341 vnl_hungarian_algorithm<T>::Step_5()
00342 {
00343   unsigned i = m_Z0_r;
00344   unsigned j = m_Z0_c;
00345   vcl_vector<unsigned> rows, cols;
00346 
00347   while ( true )
00348   {
00349     // This is the primed zero
00350     assert( m_M(i,j) == PRIME );
00351     rows.push_back( i );
00352     cols.push_back( j );
00353 
00354     // Look for a starred zero in this column
00355     for ( i = 0; i < m_N; ++i )
00356     {
00357       if ( m_M(i,j) == STAR )
00358       {
00359         break;
00360       }
00361     }
00362 
00363     if ( i == m_N )
00364     {
00365       // we didn't find a starred zero. Stop the loop
00366       break;
00367     }
00368 
00369     // This is the starred zero
00370     rows.push_back( i );
00371     cols.push_back( j );
00372 
00373     // Look for the primed zero in the row of the starred zero
00374     for ( j = 0; j < m_N; ++j )
00375     {
00376       if ( m_M(i,j) == PRIME )
00377       {
00378         break;
00379       }
00380     }
00381     assert( j < m_N ); // there should always be one
00382 
00383     // go back to the top to mark the primed zero, and repeat.
00384   }
00385 
00386   // Series has terminated. Unstar each star and star each prime in
00387   // the series.
00388   for ( unsigned idx = 0; idx < rows.size(); ++idx )
00389   {
00390     unsigned i = rows[idx];
00391     unsigned j = cols[idx];
00392     if ( m_M(i,j) == STAR )
00393     {
00394       m_M(i,j) = NORMAL; // unstar each starred zero
00395       }
00396     else
00397     {
00398       assert( m_M(i,j) == PRIME );
00399       m_M(i,j) = STAR; // star each primed zero
00400     }
00401   }
00402 
00403   // Erase all primes.
00404   for ( unsigned i = 0; i < m_N; ++i )
00405   {
00406     for ( unsigned j = 0; j < m_N; ++j )
00407     {
00408       if ( m_M(i,j) == PRIME )
00409       {
00410         m_M(i,j) = NORMAL;
00411       }
00412     }
00413   }
00414 
00415   // Uncover everything
00416   clear_vector( m_R_cov );
00417   clear_vector( m_C_cov );
00418 
00419   return STEP_3;
00420 }
00421 
00422 //-----------------------------------------------------------------------------
00423 // Step 6: Add the value found in Step 4 to every element of each
00424 // covered row, and subtract it from every element of each uncovered
00425 // column.  Return to Step 4 without altering any stars, primes, or
00426 // covered lines.
00427 //-----------------------------------------------------------------------------
00428 template <class T>
00429 typename vnl_hungarian_algorithm<T>::STEP_TYPE
00430 vnl_hungarian_algorithm<T>::Step_6()
00431 {
00432   // The value found in step 4 is the smallest uncovered value. Find it now.
00433   T minval = vcl_numeric_limits<T>::max();
00434   for ( unsigned i = 0; i < m_N; ++i )
00435   {
00436     if ( ! m_R_cov[i] )
00437     {
00438       for ( unsigned j = 0; j < m_N; ++j )
00439       {
00440         if ( ! m_C_cov[j] && m_Cost(i,j) < minval )
00441         {
00442           minval = m_Cost(i,j);
00443         }
00444       }
00445     }
00446   }
00447 
00448   // Modify the matrix as instructed.
00449   for ( unsigned i = 0; i < m_N; ++i )
00450   {
00451     for ( unsigned j = 0; j < m_N; ++j )
00452     {
00453       if ( m_R_cov[i] )
00454       {
00455         m_Cost(i,j) += minval;
00456       }
00457       if ( ! m_C_cov[j] )
00458       {
00459         m_Cost(i,j) -= minval;
00460       }
00461     }
00462   }
00463 
00464   return STEP_4;
00465 }
00466 
00467 
00468 //-----------------------------------------------------------------------------
00469 // DONE: Assignment pairs are indicated by the positions of the
00470 // starred zeros in the cost matrix.  If C(i,j) is a starred zero,
00471 // then the element associated with row i is assigned to the element
00472 // associated with column j.
00473 //-----------------------------------------------------------------------------
00474 template <class T>
00475 void
00476 vnl_hungarian_algorithm<T>::Step_done()
00477 {
00478   vcl_vector<unsigned> assign( m_Cost_in.rows(), (unsigned int)(-1) );
00479   m_AssignmentVector = assign;
00480 
00481   // Find the stars and generate the resulting assignment. Only
00482   // check the sub-matrix of cost that corresponds to the input cost
00483   // matrix. The remaining rows and columns are unassigned.
00484   for ( unsigned j = 0; j < m_Cost_in.cols(); ++j )
00485   {
00486     for ( unsigned i = 0; i < m_Cost_in.rows(); ++i )
00487     {
00488       if ( m_M(i,j) == STAR )
00489       {
00490         m_AssignmentVector[i] = j;
00491         m_TotalCost += m_Cost_in[i][j];
00492       }
00493     }
00494   }
00495 }
00496 
00497 //-----------------------------------------------------------------------------
00498 // Returns the total cost of the assignment
00499 //-----------------------------------------------------------------------------
00500 template <class T>
00501 T
00502 vnl_hungarian_algorithm<T>::GetTotalCost()
00503 {
00504   return m_TotalCost;
00505 }
00506 
00507 //-----------------------------------------------------------------------------
00508 // Returns the assignment matrix
00509 //-----------------------------------------------------------------------------
00510 template <class T>
00511 typename vnl_hungarian_algorithm<T>::AssignmentMatrixType
00512 vnl_hungarian_algorithm<T>::GetAssignmentMatrix()
00513 {
00514   return m_M;
00515 }
00516 
00517 //-----------------------------------------------------------------------------
00518 // Returns the assignment vector
00519 //-----------------------------------------------------------------------------
00520 template <class T>
00521 typename vnl_hungarian_algorithm<T>::AssignmentVectorType
00522 vnl_hungarian_algorithm<T>::GetAssignmentVector()
00523 {
00524   return m_AssignmentVector;
00525 }
00526 
00527 #undef VNL_HUNGARIAN_ALGORITHM_INSTANTIATE
00528 #define VNL_HUNGARIAN_ALGORITHM_INSTANTIATE(T) \
00529 template class vnl_hungarian_algorithm<T >
00530 
00531 #endif // vnl_hungarian_algorithm_txx_