Skip to content

Commit b06caa5

Browse files
committed
Init commit
0 parents  commit b06caa5

File tree

5 files changed

+483
-0
lines changed

5 files changed

+483
-0
lines changed

Hungarian.cpp

Lines changed: 395 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,395 @@
1+
///////////////////////////////////////////////////////////////////////////////
2+
// Hungarian.cpp: Implementation file for Class HungarianAlgorithm.
3+
//
4+
// This is a C++ wrapper with slight modification of a hungarian algorithm implementation by Markus Buehren.
5+
// The original implementation is a few mex-functions for use in MATLAB, found here:
6+
// http://www.mathworks.com/matlabcentral/fileexchange/6543-functions-for-the-rectangular-assignment-problem
7+
//
8+
// Both this code and the orignal code are published under the BSD license.
9+
// by Cong Ma, 2016
10+
//
11+
12+
#include "Hungarian.h"
13+
14+
15+
HungarianAlgorithm::HungarianAlgorithm(){}
16+
HungarianAlgorithm::~HungarianAlgorithm(){}
17+
18+
19+
//********************************************************//
20+
// A single function wrapper for solving assignment problem.
21+
//********************************************************//
22+
double HungarianAlgorithm::Solve(vector<vector<double>>& DistMatrix, vector<int>& Assignment)
23+
{
24+
unsigned int nRows = DistMatrix.size();
25+
unsigned int nCols = DistMatrix[0].size();
26+
Assignment.clear();
27+
28+
if (nRows == 0 || nCols == 0)
29+
return 0.0;
30+
31+
double *distMatrixIn = new double[nRows * nCols];
32+
int *assignment = new int[nRows];
33+
double cost = 0.0;
34+
35+
// Fill in the distMatrixIn. Mind the index is "i + nRows * j".
36+
// Here the cost matrix of size MxN is defined as a double precision array of N*M elements.
37+
// In the solving functions matrices are seen to be saved MATLAB-internally in row-order.
38+
// (i.e. the matrix [1 2; 3 4] will be stored as a vector [1 3 2 4], NOT [1 2 3 4]).
39+
for (unsigned int i = 0; i < nRows; i++)
40+
for (unsigned int j = 0; j < nCols; j++)
41+
distMatrixIn[i + nRows * j] = DistMatrix[i][j];
42+
43+
// call solving function
44+
assignmentoptimal(assignment, &cost, distMatrixIn, nRows, nCols);
45+
46+
for (unsigned int r = 0; r < nRows; r++)
47+
Assignment.push_back(assignment[r]);
48+
49+
delete[] distMatrixIn;
50+
delete[] assignment;
51+
return cost;
52+
}
53+
54+
55+
//********************************************************//
56+
// Solve optimal solution for assignment problem using Munkres algorithm, also known as Hungarian Algorithm.
57+
//********************************************************//
58+
void HungarianAlgorithm::assignmentoptimal(int *assignment, double *cost, double *distMatrixIn, int nOfRows, int nOfColumns)
59+
{
60+
double *distMatrix, *distMatrixTemp, *distMatrixEnd, *columnEnd, value, minValue;
61+
bool *coveredColumns, *coveredRows, *starMatrix, *newStarMatrix, *primeMatrix;
62+
int nOfElements, minDim, row, col;
63+
64+
/* initialization */
65+
*cost = 0;
66+
for (row = 0; row<nOfRows; row++)
67+
assignment[row] = -1;
68+
69+
/* generate working copy of distance Matrix */
70+
/* check if all matrix elements are positive */
71+
nOfElements = nOfRows * nOfColumns;
72+
distMatrix = (double *)malloc(nOfElements * sizeof(double));
73+
distMatrixEnd = distMatrix + nOfElements;
74+
75+
for (row = 0; row<nOfElements; row++)
76+
{
77+
value = distMatrixIn[row];
78+
if (value < 0)
79+
cerr << "All matrix elements have to be non-negative." << endl;
80+
distMatrix[row] = value;
81+
}
82+
83+
84+
/* memory allocation */
85+
coveredColumns = (bool *)calloc(nOfColumns, sizeof(bool));
86+
coveredRows = (bool *)calloc(nOfRows, sizeof(bool));
87+
starMatrix = (bool *)calloc(nOfElements, sizeof(bool));
88+
primeMatrix = (bool *)calloc(nOfElements, sizeof(bool));
89+
newStarMatrix = (bool *)calloc(nOfElements, sizeof(bool)); /* used in step4 */
90+
91+
/* preliminary steps */
92+
if (nOfRows <= nOfColumns)
93+
{
94+
minDim = nOfRows;
95+
96+
for (row = 0; row<nOfRows; row++)
97+
{
98+
/* find the smallest element in the row */
99+
distMatrixTemp = distMatrix + row;
100+
minValue = *distMatrixTemp;
101+
distMatrixTemp += nOfRows;
102+
while (distMatrixTemp < distMatrixEnd)
103+
{
104+
value = *distMatrixTemp;
105+
if (value < minValue)
106+
minValue = value;
107+
distMatrixTemp += nOfRows;
108+
}
109+
110+
/* subtract the smallest element from each element of the row */
111+
distMatrixTemp = distMatrix + row;
112+
while (distMatrixTemp < distMatrixEnd)
113+
{
114+
*distMatrixTemp -= minValue;
115+
distMatrixTemp += nOfRows;
116+
}
117+
}
118+
119+
/* Steps 1 and 2a */
120+
for (row = 0; row<nOfRows; row++)
121+
for (col = 0; col<nOfColumns; col++)
122+
if (fabs(distMatrix[row + nOfRows*col]) < DBL_EPSILON)
123+
if (!coveredColumns[col])
124+
{
125+
starMatrix[row + nOfRows*col] = true;
126+
coveredColumns[col] = true;
127+
break;
128+
}
129+
}
130+
else /* if(nOfRows > nOfColumns) */
131+
{
132+
minDim = nOfColumns;
133+
134+
for (col = 0; col<nOfColumns; col++)
135+
{
136+
/* find the smallest element in the column */
137+
distMatrixTemp = distMatrix + nOfRows*col;
138+
columnEnd = distMatrixTemp + nOfRows;
139+
140+
minValue = *distMatrixTemp++;
141+
while (distMatrixTemp < columnEnd)
142+
{
143+
value = *distMatrixTemp++;
144+
if (value < minValue)
145+
minValue = value;
146+
}
147+
148+
/* subtract the smallest element from each element of the column */
149+
distMatrixTemp = distMatrix + nOfRows*col;
150+
while (distMatrixTemp < columnEnd)
151+
*distMatrixTemp++ -= minValue;
152+
}
153+
154+
/* Steps 1 and 2a */
155+
for (col = 0; col<nOfColumns; col++)
156+
for (row = 0; row<nOfRows; row++)
157+
if (fabs(distMatrix[row + nOfRows*col]) < DBL_EPSILON)
158+
if (!coveredRows[row])
159+
{
160+
starMatrix[row + nOfRows*col] = true;
161+
coveredColumns[col] = true;
162+
coveredRows[row] = true;
163+
break;
164+
}
165+
for (row = 0; row<nOfRows; row++)
166+
coveredRows[row] = false;
167+
168+
}
169+
170+
/* move to step 2b */
171+
step2b(assignment, distMatrix, starMatrix, newStarMatrix, primeMatrix, coveredColumns, coveredRows, nOfRows, nOfColumns, minDim);
172+
173+
/* compute cost and remove invalid assignments */
174+
computeassignmentcost(assignment, cost, distMatrixIn, nOfRows);
175+
176+
/* free allocated memory */
177+
free(distMatrix);
178+
free(coveredColumns);
179+
free(coveredRows);
180+
free(starMatrix);
181+
free(primeMatrix);
182+
free(newStarMatrix);
183+
184+
return;
185+
}
186+
187+
/********************************************************/
188+
void HungarianAlgorithm::buildassignmentvector(int *assignment, bool *starMatrix, int nOfRows, int nOfColumns)
189+
{
190+
int row, col;
191+
192+
for (row = 0; row<nOfRows; row++)
193+
for (col = 0; col<nOfColumns; col++)
194+
if (starMatrix[row + nOfRows*col])
195+
{
196+
#ifdef ONE_INDEXING
197+
assignment[row] = col + 1; /* MATLAB-Indexing */
198+
#else
199+
assignment[row] = col;
200+
#endif
201+
break;
202+
}
203+
}
204+
205+
/********************************************************/
206+
void HungarianAlgorithm::computeassignmentcost(int *assignment, double *cost, double *distMatrix, int nOfRows)
207+
{
208+
int row, col;
209+
210+
for (row = 0; row<nOfRows; row++)
211+
{
212+
col = assignment[row];
213+
if (col >= 0)
214+
*cost += distMatrix[row + nOfRows*col];
215+
}
216+
}
217+
218+
/********************************************************/
219+
void HungarianAlgorithm::step2a(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix, bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim)
220+
{
221+
bool *starMatrixTemp, *columnEnd;
222+
int col;
223+
224+
/* cover every column containing a starred zero */
225+
for (col = 0; col<nOfColumns; col++)
226+
{
227+
starMatrixTemp = starMatrix + nOfRows*col;
228+
columnEnd = starMatrixTemp + nOfRows;
229+
while (starMatrixTemp < columnEnd){
230+
if (*starMatrixTemp++)
231+
{
232+
coveredColumns[col] = true;
233+
break;
234+
}
235+
}
236+
}
237+
238+
/* move to step 3 */
239+
step2b(assignment, distMatrix, starMatrix, newStarMatrix, primeMatrix, coveredColumns, coveredRows, nOfRows, nOfColumns, minDim);
240+
}
241+
242+
/********************************************************/
243+
void HungarianAlgorithm::step2b(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix, bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim)
244+
{
245+
int col, nOfCoveredColumns;
246+
247+
/* count covered columns */
248+
nOfCoveredColumns = 0;
249+
for (col = 0; col<nOfColumns; col++)
250+
if (coveredColumns[col])
251+
nOfCoveredColumns++;
252+
253+
if (nOfCoveredColumns == minDim)
254+
{
255+
/* algorithm finished */
256+
buildassignmentvector(assignment, starMatrix, nOfRows, nOfColumns);
257+
}
258+
else
259+
{
260+
/* move to step 3 */
261+
step3(assignment, distMatrix, starMatrix, newStarMatrix, primeMatrix, coveredColumns, coveredRows, nOfRows, nOfColumns, minDim);
262+
}
263+
264+
}
265+
266+
/********************************************************/
267+
void HungarianAlgorithm::step3(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix, bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim)
268+
{
269+
bool zerosFound;
270+
int row, col, starCol;
271+
272+
zerosFound = true;
273+
while (zerosFound)
274+
{
275+
zerosFound = false;
276+
for (col = 0; col<nOfColumns; col++)
277+
if (!coveredColumns[col])
278+
for (row = 0; row<nOfRows; row++)
279+
if ((!coveredRows[row]) && (fabs(distMatrix[row + nOfRows*col]) < DBL_EPSILON))
280+
{
281+
/* prime zero */
282+
primeMatrix[row + nOfRows*col] = true;
283+
284+
/* find starred zero in current row */
285+
for (starCol = 0; starCol<nOfColumns; starCol++)
286+
if (starMatrix[row + nOfRows*starCol])
287+
break;
288+
289+
if (starCol == nOfColumns) /* no starred zero found */
290+
{
291+
/* move to step 4 */
292+
step4(assignment, distMatrix, starMatrix, newStarMatrix, primeMatrix, coveredColumns, coveredRows, nOfRows, nOfColumns, minDim, row, col);
293+
return;
294+
}
295+
else
296+
{
297+
coveredRows[row] = true;
298+
coveredColumns[starCol] = false;
299+
zerosFound = true;
300+
break;
301+
}
302+
}
303+
}
304+
305+
/* move to step 5 */
306+
step5(assignment, distMatrix, starMatrix, newStarMatrix, primeMatrix, coveredColumns, coveredRows, nOfRows, nOfColumns, minDim);
307+
}
308+
309+
/********************************************************/
310+
void HungarianAlgorithm::step4(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix, bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim, int row, int col)
311+
{
312+
int n, starRow, starCol, primeRow, primeCol;
313+
int nOfElements = nOfRows*nOfColumns;
314+
315+
/* generate temporary copy of starMatrix */
316+
for (n = 0; n<nOfElements; n++)
317+
newStarMatrix[n] = starMatrix[n];
318+
319+
/* star current zero */
320+
newStarMatrix[row + nOfRows*col] = true;
321+
322+
/* find starred zero in current column */
323+
starCol = col;
324+
for (starRow = 0; starRow<nOfRows; starRow++)
325+
if (starMatrix[starRow + nOfRows*starCol])
326+
break;
327+
328+
while (starRow<nOfRows)
329+
{
330+
/* unstar the starred zero */
331+
newStarMatrix[starRow + nOfRows*starCol] = false;
332+
333+
/* find primed zero in current row */
334+
primeRow = starRow;
335+
for (primeCol = 0; primeCol<nOfColumns; primeCol++)
336+
if (primeMatrix[primeRow + nOfRows*primeCol])
337+
break;
338+
339+
/* star the primed zero */
340+
newStarMatrix[primeRow + nOfRows*primeCol] = true;
341+
342+
/* find starred zero in current column */
343+
starCol = primeCol;
344+
for (starRow = 0; starRow<nOfRows; starRow++)
345+
if (starMatrix[starRow + nOfRows*starCol])
346+
break;
347+
}
348+
349+
/* use temporary copy as new starMatrix */
350+
/* delete all primes, uncover all rows */
351+
for (n = 0; n<nOfElements; n++)
352+
{
353+
primeMatrix[n] = false;
354+
starMatrix[n] = newStarMatrix[n];
355+
}
356+
for (n = 0; n<nOfRows; n++)
357+
coveredRows[n] = false;
358+
359+
/* move to step 2a */
360+
step2a(assignment, distMatrix, starMatrix, newStarMatrix, primeMatrix, coveredColumns, coveredRows, nOfRows, nOfColumns, minDim);
361+
}
362+
363+
/********************************************************/
364+
void HungarianAlgorithm::step5(int *assignment, double *distMatrix, bool *starMatrix, bool *newStarMatrix, bool *primeMatrix, bool *coveredColumns, bool *coveredRows, int nOfRows, int nOfColumns, int minDim)
365+
{
366+
double h, value;
367+
int row, col;
368+
369+
/* find smallest uncovered element h */
370+
h = DBL_MAX;
371+
for (row = 0; row<nOfRows; row++)
372+
if (!coveredRows[row])
373+
for (col = 0; col<nOfColumns; col++)
374+
if (!coveredColumns[col])
375+
{
376+
value = distMatrix[row + nOfRows*col];
377+
if (value < h)
378+
h = value;
379+
}
380+
381+
/* add h to each covered row */
382+
for (row = 0; row<nOfRows; row++)
383+
if (coveredRows[row])
384+
for (col = 0; col<nOfColumns; col++)
385+
distMatrix[row + nOfRows*col] += h;
386+
387+
/* subtract h from each uncovered column */
388+
for (col = 0; col<nOfColumns; col++)
389+
if (!coveredColumns[col])
390+
for (row = 0; row<nOfRows; row++)
391+
distMatrix[row + nOfRows*col] -= h;
392+
393+
/* move to step 3 */
394+
step3(assignment, distMatrix, starMatrix, newStarMatrix, primeMatrix, coveredColumns, coveredRows, nOfRows, nOfColumns, minDim);
395+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy