1 /********************************************************************
2 ********************************************************************
4 ** libhungarian by Cyrill Stachniss, 2004
5 ** Modified by Benjamin Auder to work on floating point number,
6 ** and to fit into a R package (2017)
8 ** Solving the Minimum Assignment Problem using the Hungarian Method.
10 ** ** This file may be freely copied and distributed! **
12 ** Parts of the used code was originally provided by the
13 ** "Stanford GraphGase", but I made changes to this code.
14 ** As asked by the copyright node of the "Stanford GraphGase",
15 ** I hereby proclaim that this file are *NOT* part of the
16 ** "Stanford GraphGase" distrubition!
18 ** This file is distributed in the hope that it will be useful,
19 ** but WITHOUT ANY WARRANTY; without even the implied
20 ** warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
23 ********************************************************************
24 ********************************************************************/
29 #define HUNGARIAN_NOT_ASSIGNED 0
30 #define HUNGARIAN_ASSIGNED 1
32 #define HUNGARIAN_MODE_MINIMIZE_COST 0
33 #define HUNGARIAN_MODE_MAXIMIZE_UTIL 1
43 } hungarian_problem_t
;
45 int hungarian_imax(int a
, int b
) {
49 /** This method initialize the hungarian_problem structure and init
50 * the cost matrices (missing lines or columns are filled with 0).
51 * It returns the size of the quadratic(!) assignment matrix. **/
52 int hungarian_init(hungarian_problem_t
* p
, double** cost_matrix
, int rows
, int cols
,
60 // is the number of cols not equal to number of rows ?
61 // if yes, expand with 0-cols / 0-cols
62 rows
= hungarian_imax(cols
, rows
);
68 p
->cost
= (double**)calloc(rows
,sizeof(double*));
69 p
->assignment
= (int**)calloc(rows
,sizeof(int*));
71 for(i
=0; i
<p
->num_rows
; i
++) {
72 p
->cost
[i
] = (double*)calloc(cols
,sizeof(double));
73 p
->assignment
[i
] = (int*)calloc(cols
,sizeof(int));
74 for(j
=0; j
<p
->num_cols
; j
++) {
75 p
->cost
[i
][j
] = (i
< org_rows
&& j
< org_cols
) ? cost_matrix
[i
][j
] : 0.;
76 p
->assignment
[i
][j
] = 0;
78 if (max_cost
< p
->cost
[i
][j
])
79 max_cost
= p
->cost
[i
][j
];
83 if (mode
== HUNGARIAN_MODE_MAXIMIZE_UTIL
) {
84 for(i
=0; i
<p
->num_rows
; i
++) {
85 for(j
=0; j
<p
->num_cols
; j
++)
86 p
->cost
[i
][j
] = max_cost
- p
->cost
[i
][j
];
89 else if (mode
== HUNGARIAN_MODE_MINIMIZE_COST
) {
93 // fprintf(stderr,"%s: unknown mode. Mode was set to HUNGARIAN_MODE_MINIMIZE_COST !\n", __FUNCTION__);
98 /** Free the memory allocated by init. **/
99 void hungarian_free(hungarian_problem_t
* p
) {
101 for(i
=0; i
<p
->num_rows
; i
++) {
103 free(p
->assignment
[i
]);
108 p
->assignment
= NULL
;
111 /** This method computes the optimal assignment. **/
112 void hungarian_solve(hungarian_problem_t
* p
)
114 int i
, j
, m
, n
, k
, l
, t
, q
, unmatched
;
129 col_mate
= (int*)calloc(p
->num_rows
,sizeof(int));
130 unchosen_row
= (int*)calloc(p
->num_rows
,sizeof(int));
131 row_dec
= (double*)calloc(p
->num_rows
,sizeof(double));
132 slack_row
= (int*)calloc(p
->num_rows
,sizeof(int));
134 row_mate
= (int*)calloc(p
->num_cols
,sizeof(int));
135 parent_row
= (int*)calloc(p
->num_cols
,sizeof(int));
136 col_inc
= (double*)calloc(p
->num_cols
,sizeof(double));
137 slack
= (double*)calloc(p
->num_cols
,sizeof(double));
139 for (i
=0; i
<p
->num_rows
; i
++) {
145 for (j
=0; j
<p
->num_cols
; j
++) {
152 for (i
=0; i
<p
->num_rows
; ++i
)
153 for (j
=0; j
<p
->num_cols
; ++j
)
154 p
->assignment
[i
][j
]=HUNGARIAN_NOT_ASSIGNED
;
156 // Begin subtract column minima in order to start with lots of zeroes 12
168 // End subtract column minima in order to start with lots of zeroes 12
170 // Begin initial state 16
187 if (s
==p
->cost
[k
][l
] && row_mate
[l
]<0)
198 // End initial state 16
200 // Begin Hungarian algorithm 18
211 // Begin explore node q of the forest 19
218 double del
=p
->cost
[k
][l
]-s
+col_inc
[l
];
227 unchosen_row
[t
++]=row_mate
[l
];
237 // End explore node q of the forest 19
241 // Begin introduce a new zero into the matrix 21
244 if (slack
[l
]>0. && slack
[l
]<s
)
247 row_dec
[unchosen_row
[q
]]+=s
;
254 // Begin look at a new zero 22
258 for (j
=l
+1; j
<n
; j
++)
266 unchosen_row
[t
++]=row_mate
[l
];
268 // End look at a new zero 22
273 // End introduce a new zero into the matrix 21
276 // Begin update the matching 20
287 // End update the matching 20
290 // Begin get ready for another stage 17
300 // End get ready for another stage 17
304 /* // Begin doublecheck the solution 23
307 if (p->cost[k][l]<row_dec[k]-col_inc[l])
312 if (l<0 || p->cost[k][l]!=row_dec[k]-col_inc[l])
321 // End doublecheck the solution 23
322 */ // End Hungarian algorithm 18
326 p
->assignment
[i
][col_mate
[i
]]=HUNGARIAN_ASSIGNED
;
327 /*TRACE("%d - %d\n", i, col_mate[i]);*/
333 /*TRACE("%d ",p->cost[k][l]-row_dec[k]+col_inc[l]);*/
334 p
->cost
[k
][l
]=p
->cost
[k
][l
]-row_dec
[k
]+col_inc
[l
];
338 /* for (i=0; i<m; i++)
358 // Auxiliary function for hungarianAlgorithm below
359 double** array_to_matrix(double* m
, int rows
, int cols
)
361 double** r
= (double**)calloc(rows
,sizeof(double*));
362 for (int i
=0; i
<rows
; i
++)
364 r
[i
] = (double*)calloc(cols
,sizeof(double));
365 for (int j
=0; j
<cols
; j
++)
366 r
[i
][j
] = m
[i
*cols
+j
];
371 //TODO: re-code this algorithm in a more readable way, based on
372 //https://www.topcoder.com/community/data-science/data-science-tutorials/assignment-problem-and-hungarian-algorithm/
373 // Get the optimal assignment, by calling hungarian_solve above; "distances" in columns
374 void hungarianAlgorithm(double* distances
, int* pn
, int* assignment
)
377 double** mat
= array_to_matrix(distances
, n
, n
);
379 hungarian_problem_t p
;
380 hungarian_init(&p
, mat
, n
, n
, HUNGARIAN_MODE_MINIMIZE_COST
);
384 // Copy the optimal assignment in a R-friendly structure
385 for (int i
=0; i
< n
; i
++) {
386 for (int j
=0; j
< n
; j
++) {
387 if (p
.assignment
[i
][j
])
388 assignment
[i
] = j
+1; //add 1 since we work with R
393 for (int i
=0; i
<n
; i
++)