ATLAS Offline Software
Loading...
Searching...
No Matches
munkres.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "munkres.h"
6#include "boost/io/ios_state.hpp"
7
9 m_costmatrix(costs),
10 m_costs_orig(costs),
11 m_step(0),
12 m_dim(costs.size())
13{
14 m_rowIsCovered = std::vector<bool>(m_dim,false);
15 m_colIsCovered = std::vector<bool>(m_dim,false);
16 vec_type maskrow(m_dim,0);
17 for(int i=0;i<m_dim;++i) m_maskmatrix.push_back(maskrow);
18}
19
21 if(debug) printcosts();
22 bool done = false;
23 m_step = 1;
24 while(!done){
25 if(debug){
26 std::cout << "doing step " << m_step << std::endl;
27 printcosts();
28 printmask();
29 }
30 switch(m_step){
31 case 1:
32 step_one();
33 break;
34 case 2:
35 step_two();
36 break;
37 case 3:
38 step_three();
39 break;
40 case 4:
41 step_four();
42 break;
43 case 5:
44 step_five();
45 break;
46 case 6:
47 step_six();
48 break;
49 case 7:
50 done = true;
51 break;
52 }
53 }
54 if(debug) std::cout << "done running munkres algorithm: " << std::endl;
56 costvector.clear();
57
58 for(int row=0;row<m_dim;++row){
59 int col = find_in_row(row,kStar);
60 result.push_back(col);
61 costvector.push_back(m_costs_orig[row][result.back()]);
62 }
63
64 if(debug){
65 printcosts();
66 for(uint i=0;i<result.size();++i) std::cout << "row: " << i << " -> col: " << result[i] << " cost: " << m_costs_orig[i][result[i]]<< std::endl;
67 }
68 return result;
69}
70
72 //subtract row minimum from each row element
73 //then go to step 2
74 for(int row=0;row<m_dim;++row){
75 double min = m_costmatrix[row][0];
76 for(int col=0;col<m_dim;++col){ // find minimum
77 if(m_costmatrix[row][col] < min) min = m_costmatrix[row][col];
78 }
79 for(int col=0;col<m_dim;++col){ // subtract from all elements
80 m_costmatrix[row][col] -= min;
81 }
82 }
83 m_step = 2;
84}
85
87 //star a zero matrix element if there is no other zero in it column or row
88 //we will cover each row and column that have a zero so we know we don't have to
89 //check these rows and columns anymore for zeros to star
90 //then go to step 3
91
92 for(int row=0;row<m_dim;++row){
93 for(int col=0;col<m_dim;++col){
94 if(!m_rowIsCovered[row] && !m_colIsCovered[col] && m_costmatrix[row][col] == 0){
95 m_rowIsCovered[row] = true;
96 m_colIsCovered[col] = true;
97 m_maskmatrix[row][col] = 1;
98 }
99 }
100 }
101 //reset cover vectors
102 for(int i=0;i<m_dim;++i){
103 m_rowIsCovered[i] = false;
104 m_colIsCovered[i] = false;
105 }
106 m_step = 3;
107}
108
110 //cover each column with a starred zero
111 //if we have m_dim coered columns we're done and exit
112 //else we continue with step four
113
114 for(int row=0;row<m_dim;++row){
115 for(int col=0;col<m_dim;++col){
116 if(m_maskmatrix[row][col] == 1) m_colIsCovered[col] = true; // this is a starred zero cover column
117 }
118 }
119
120 int nCoveredCols = 0;
121 for(int col=0;col<m_dim;++col) if(m_colIsCovered[col]) nCoveredCols++;
122
123 m_step = (nCoveredCols == m_dim) ? 7 : 4;
124}
125
126void munkres::find_a_zero(int& row, int& col){
127 for(row=0;row<m_dim;++row){
128 for(col=0;col<m_dim;++col){
129 if(m_costmatrix[row][col] == 0 && !m_colIsCovered[col] && !m_rowIsCovered[row]) return;
130 }
131 }
132 //not returned until now set flags
133 row = -1;
134 col = -1;
135}
136
137int munkres::find_in_row(const int row, markertype what){
138 for(int col = 0;col<m_dim;++col) if(m_maskmatrix[row][col] == what) return col;
139 //not returned until now
140 return -1;
141}
142
143int munkres::find_in_col(const int col, markertype what){
144 for(int row = 0;row<m_dim;++row) if(m_maskmatrix[row][col] == what) return row;
145 //not returned until now
146 return -1;
147}
148
150 // Find a noncovered zero and prime it.
151 // If there is no starred zero in the row containing this primed zero, Go to Step 5.
152 // Otherwise, cover this row and uncover the column containing the starred zero.
153 // Continue in this manner until there are no uncovered zeros left.
154 // Save the smallest uncovered value and Go to Step 6.
155
156 bool done = false;
157 while(!done){
158 int row, col;
159 find_a_zero(row,col);
160 if(row == -1){
161 //there is no uncovered zero go to step 6
162 done = true;
163 m_step = 6;
164 }
165 else{
166 // std::cout << "found uncovered zero at " << row << ", " << col << std::endl;
167 //check if there is a starred zero in this row
168 m_maskmatrix[row][col]=2;
169 int starred0atcol = find_in_row(row,kStar);
170 if(starred0atcol != -1){
171 m_rowIsCovered[row] = true;
172 m_colIsCovered[starred0atcol] = false;
173 // printcosts();
174 // printmask();
175 }else{
176 done = true;
177 m_step = 5;
178 }
179 }
180 }
181}
182
183void munkres::augment_path(const std::vector<coords>& p){
184 for(unsigned int i = 0;i<p.size();++i){
185 const int row = p[i].first;
186 const int col = p[i].second;
187 if(m_maskmatrix[row][col] == kStar){
188 m_maskmatrix[row][col] = 0; //unstar each star;
189 }
190 else{//primed zeros
191 m_maskmatrix[row][col] = kStar; //star each primed and unprime it;
192 }
193 }
194}
195
197 for(int row=0;row<m_dim;++row){
198 m_rowIsCovered[row] = false;
199 m_colIsCovered[row] = false;//queadratic matrix
200 for(int col=0;col<m_dim;++col){
201 if(m_maskmatrix[row][col] == kPrime) m_maskmatrix[row][col] = 0;
202 }
203 }
204}
205
207 // Construct a series of alternating primed and starred zeros as follows.
208 // Let Z0 represent the uncovered primed zero found in Step 4.
209 // Let Z1 denote the starred zero in the column of Z0 (if any).
210 // Let Z2 denote the primed zero in the row of Z1 (there will always be one).
211 // Continue until the series terminates at a primed zero that has no starred zero in its column.
212 // Unstar each starred zero of the series, star each primed zero of the series,
213 // erase all primes and uncover every line in the matrix. Return to Step 3.
214
215 bool done = false;
216 std::vector<coords> path;
217 int row,col;
218 find_a_zero(row,col);
219
220 path.push_back(coords(row,col));
221
222 int n = 0;
223 while(!done && n<4){n++;
224 int starred0atrow = find_in_col(path.back().second,kStar);
225 if(starred0atrow > -1){
226 path.push_back(coords(starred0atrow,path.back().second));
227 }
228 else{
229 done = true;
230 }
231 if(!done){
232 int primed0atcol = find_in_row(path.back().first,kPrime);
233 path.push_back(coords(path.back().first,primed0atcol));
234 }
235 }
236 // std::cout << "found path: " << std::endl;
237 // for(unsigned int i=0;i<path.size();++i){
238 // std::cout << "(" << path[i].first << "," << path[i].second << ")" << ((i<path.size()-1) ? "->" : "" );
239 // } std::cout << std::endl;
240
241 augment_path(path);
243
244 m_step = 3;
245}
246
248 double min = 1e10;
249 for(int row=0;row<m_dim;++row){
250 for(int col=0;col<m_dim;++col){
251 if(!m_rowIsCovered[row] && !m_colIsCovered[col] && m_costmatrix[row][col] < min){
252 min = m_costmatrix[row][col];
253 }
254 }
255 }
256 return min;
257}
258
260 // Add the value found in Step 4 to every element of each covered row,
261 // and subtract it from every element of each uncovered column.
262 // Return to Step 4 without altering any stars, primes, or covered lines.
263 // Notice that this step uses the smallest uncovered value in the cost matrix to modify the matrix.
264
265 double minuncov = find_min_uncov();
266 for(int row=0;row<m_dim;++row){
267 for(int col=0;col<m_dim;++col){
268 if(m_rowIsCovered[row]) m_costmatrix[row][col] += minuncov;
269 if(!m_colIsCovered[col]) m_costmatrix[row][col] -= minuncov;
270 }
271 }
272 m_step = 4;
273}
274
276 boost::io::ios_all_saver ias(std::cout);
277 std::cout << std::setw(5) << std::setprecision(3) << "cov|";
278 for(int col=0;col<m_dim;++col){
279 std::cout << std::setw(7) << std::setprecision(3) << (m_colIsCovered[col] ? "+|" : "|");
280 } std::cout << std::endl;
281
282 for(int row=0;row<m_dim;++row){
283 std::cout << std::setw(5) << std::setprecision(3) << (m_rowIsCovered[row] ? "+ |" : "|");
284 for(int col=0;col<m_dim;++col){
285 std::cout << std::setw(5) << std::setprecision(3) << m[row][col];
286 if(m_maskmatrix[row][col] == kPrime) std::cout << "'";
287 if(m_maskmatrix[row][col] == kStar) std::cout << "*";
288 else std::cout << " ";
289 std::cout << "|";
290 } std::cout << std::endl;
291 }
292}
unsigned int uint
const bool debug
#define min(a, b)
Definition cfImp.cxx:40
munkres(matrix_type costs)
Definition munkres.cxx:8
int m_step
Definition munkres.h:52
int find_in_col(const int col, markertype what)
Definition munkres.cxx:143
markertype
Definition munkres.h:24
@ kStar
Definition munkres.h:24
@ kPrime
Definition munkres.h:24
const int m_dim
Definition munkres.h:56
void augment_path(const std::vector< coords > &path)
Definition munkres.cxx:183
std::vector< vec_type > matrix_type
Definition munkres.h:20
void erase_primes_and_covers()
Definition munkres.cxx:196
void step_one()
Definition munkres.cxx:71
void printmatrix(const matrix_type &)
Definition munkres.cxx:275
double find_min_uncov()
Definition munkres.cxx:247
void step_three()
Definition munkres.cxx:109
void find_a_zero(int &row, int &col)
Definition munkres.cxx:126
result_type run(vec_type &costvector, bool debug=false)
Definition munkres.cxx:20
void printmask()
Definition munkres.h:38
matrix_type m_maskmatrix
Definition munkres.h:51
std::vector< int > result_type
Definition munkres.h:22
std::vector< bool > m_colIsCovered
Definition munkres.h:55
void step_six()
Definition munkres.cxx:259
void printcosts()
Definition munkres.h:27
std::vector< double > vec_type
Definition munkres.h:19
void step_four()
Definition munkres.cxx:149
int find_in_row(const int row, markertype what)
Definition munkres.cxx:137
matrix_type m_costs_orig
Definition munkres.h:50
std::pair< int, int > coords
Definition munkres.h:21
matrix_type m_costmatrix
Definition munkres.h:49
std::vector< bool > m_rowIsCovered
Definition munkres.h:54
void step_two()
Definition munkres.cxx:86
void step_five()
Definition munkres.cxx:206