Commit e1c05b01 authored by Matthias Braun's avatar Matthias Braun
Browse files

cleanup, simplify hungarian algorithm implementation

[r27900]
parent 5416fa0f
......@@ -52,19 +52,20 @@ typedef struct hungarian_problem_t hungarian_problem_t;
* This method initialize the hungarian_problem structure and init
* the cost matrix (missing lines or columns are filled with 0).
*
* @param rows Number of rows in the given matrix
* @param cols Number of cols in the given matrix
* @param num_rows Number of rows in the given matrix
* @param num_cols Number of cols in the given matrix
* @param match_type The type of matching
* @return The problem object.
*/
FIRM_API hungarian_problem_t *hungarian_new(unsigned rows, unsigned cols,
FIRM_API hungarian_problem_t *hungarian_new(unsigned num_rows,
unsigned num_cols,
match_type_t match_type);
/**
* Adds an edge from left to right with some costs.
*/
FIRM_API void hungarian_add(hungarian_problem_t *p, unsigned left,
unsigned right, int cost);
unsigned right, unsigned cost);
/**
* Removes the edge from left to right.
......@@ -95,7 +96,7 @@ FIRM_API void hungarian_free(hungarian_problem_t *p);
* @return 0 on success, negative number otherwise
*/
FIRM_API int hungarian_solve(hungarian_problem_t *p, unsigned *assignment,
int *final_cost, int cost_threshold);
unsigned *final_cost, unsigned cost_threshold);
/**
* Print the cost matrix.
......
......@@ -38,35 +38,35 @@
#include "irtools.h"
#include "xmalloc.h"
#include "debug.h"
#include "obst.h"
#include "bitset.h"
#include "error.h"
#include "hungarian.h"
DEBUG_ONLY(static firm_dbg_module_t *dbg);
struct hungarian_problem_t {
unsigned num_rows; /**< number of rows */
unsigned num_cols; /**< number of columns */
int **cost; /**< the cost matrix */
int max_cost; /**< the maximal costs in the matrix */
int match_type; /**< PERFECT or NORMAL matching */
bitset_t *missing_left; /**< left side nodes having no edge to the right side */
bitset_t *missing_right; /**< right side nodes having no edge to the left side */
struct obstack obst;
DEBUG_ONLY(firm_dbg_module_t *dbg);
unsigned num_rows; /**< number of rows */
unsigned num_cols; /**< number of columns */
unsigned *cost; /**< the cost matrix */
unsigned max_cost; /**< the maximal costs in the matrix */
match_type_t match_type; /**< PERFECT or NORMAL matching */
unsigned *missing_left; /**< bitset: left side nodes having no edge to
the right side */
unsigned *missing_right; /**< bitset: right side nodes having no edge to
the left side */
};
static void hungarian_dump_f(FILE *f, int **C, unsigned n_rows, unsigned n_cols,
int width)
static void hungarian_dump_f(FILE *f, const unsigned *cost,
unsigned num_rows, unsigned num_cols, int width)
{
unsigned r;
unsigned r, c;
fprintf(f , "\n");
for (r = 0; r < n_rows; r++) {
unsigned c;
for (r = 0; r < num_rows; r++) {
fprintf(f, " [");
for (c = 0; c < n_cols; c++) {
fprintf(f, "%*d", width, C[r][c]);
for (c = 0; c < num_cols; c++) {
fprintf(f, "%*u", width, cost[r*num_cols + c]);
}
fprintf(f, "]\n");
}
......@@ -78,25 +78,22 @@ void hungarian_print_cost_matrix(hungarian_problem_t *p, int width)
hungarian_dump_f(stderr, p->cost, p->num_rows, p->num_cols, width);
}
hungarian_problem_t *hungarian_new(unsigned n_rows, unsigned n_cols,
hungarian_problem_t *hungarian_new(unsigned num_rows, unsigned num_cols,
match_type_t match_type)
{
unsigned r;
hungarian_problem_t *p = XMALLOCZ(hungarian_problem_t);
FIRM_DBG_REGISTER(p->dbg, "firm.hungarian");
FIRM_DBG_REGISTER(dbg, "firm.hungarian");
/*
Is the number of cols not equal to number of rows ?
If yes, expand with 0 - cols / 0 - cols
*/
n_rows = MAX(n_cols, n_rows);
n_cols = n_rows;
obstack_init(&p->obst);
num_rows = MAX(num_cols, num_rows);
num_cols = num_rows;
p->num_rows = n_rows;
p->num_cols = n_cols;
p->num_rows = num_rows;
p->num_cols = num_cols;
p->match_type = match_type;
/*
......@@ -105,29 +102,28 @@ hungarian_problem_t *hungarian_new(unsigned n_rows, unsigned n_cols,
the assignment later.
*/
if (match_type == HUNGARIAN_MATCH_NORMAL) {
p->missing_left = bitset_obstack_alloc(&p->obst, n_rows);
p->missing_right = bitset_obstack_alloc(&p->obst, n_cols);
bitset_set_all(p->missing_left);
bitset_set_all(p->missing_right);
p->missing_left = rbitset_malloc(num_rows);
p->missing_right = rbitset_malloc(num_cols);
rbitset_set_all(p->missing_left, num_rows);
rbitset_set_all(p->missing_right, num_cols);
}
/* allocate space for cost matrix */
p->cost = OALLOCNZ(&p->obst, int*, n_rows);
for (r = 0; r < p->num_rows; r++)
p->cost[r] = OALLOCNZ(&p->obst, int, n_cols);
p->cost = XMALLOCNZ(unsigned, num_rows * num_cols);
return p;
}
void hungarian_prepare_cost_matrix(hungarian_problem_t *p,
hungarian_mode_t mode)
{
unsigned r, c;
if (mode == HUNGARIAN_MODE_MAXIMIZE_UTIL) {
unsigned r, c;
unsigned num_cols = p->num_cols;
unsigned *cost = p->cost;
unsigned max_cost = p->max_cost;
for (r = 0; r < p->num_rows; r++) {
for (c = 0; c < p->num_cols; c++) {
p->cost[r][c] = p->max_cost - p->cost[r][c];
cost[r*num_cols + c] = max_cost - cost[r*num_cols + c];
}
}
} else if (mode == HUNGARIAN_MODE_MINIMIZE_COST) {
......@@ -138,18 +134,17 @@ void hungarian_prepare_cost_matrix(hungarian_problem_t *p,
}
void hungarian_add(hungarian_problem_t *p, unsigned left, unsigned right,
int cost)
unsigned cost)
{
assert(p->num_rows > left && "Invalid row selected.");
assert(p->num_cols > right && "Invalid column selected.");
assert(cost >= 0);
p->cost[left][right] = cost;
p->max_cost = MAX(p->max_cost, cost);
p->cost[left*p->num_cols + right] = cost;
p->max_cost = MAX(p->max_cost, cost);
if (p->match_type == HUNGARIAN_MATCH_NORMAL) {
bitset_clear(p->missing_left, left);
bitset_clear(p->missing_right, right);
rbitset_clear(p->missing_left, left);
rbitset_clear(p->missing_right, right);
}
}
......@@ -158,35 +153,37 @@ void hungarian_remove(hungarian_problem_t *p, unsigned left, unsigned right)
assert(p->num_rows > left && "Invalid row selected.");
assert(p->num_cols > right && "Invalid column selected.");
/* Set cost[left][right] to 0. */
p->cost[left][right] = 0;
p->cost[left*p->num_cols + right] = 0;
if (p->match_type == HUNGARIAN_MATCH_NORMAL) {
bitset_set(p->missing_left, left);
bitset_set(p->missing_right, right);
rbitset_set(p->missing_left, left);
rbitset_set(p->missing_right, right);
}
}
void hungarian_free(hungarian_problem_t* p)
{
obstack_free(&p->obst, NULL);
xfree(p->missing_left);
xfree(p->missing_right);
xfree(p->cost);
xfree(p);
}
int hungarian_solve(hungarian_problem_t* p, unsigned *assignment,
int *final_cost, int cost_threshold)
unsigned *final_cost, unsigned cost_threshold)
{
int cost = 0;
unsigned num_rows = p->num_rows;
unsigned num_cols = p->num_cols;
unsigned *col_mate = XMALLOCNZ(unsigned, num_rows);
unsigned *row_mate = XMALLOCNZ(unsigned, num_cols);
unsigned *parent_row = XMALLOCNZ(unsigned, num_cols);
unsigned *unchosen_row = XMALLOCNZ(unsigned, num_rows);
int *row_dec = XMALLOCNZ(int, num_rows);
int *col_inc = XMALLOCNZ(int, num_cols);
int *slack = XMALLOCNZ(int, num_cols);
unsigned *slack_row = XMALLOCNZ(unsigned, num_rows);
unsigned res_cost = 0;
unsigned num_rows = p->num_rows;
unsigned num_cols = p->num_cols;
unsigned *cost = p->cost;
unsigned *col_mate = XMALLOCNZ(unsigned, num_rows);
unsigned *row_mate = XMALLOCNZ(unsigned, num_cols);
unsigned *parent_row = XMALLOCNZ(unsigned, num_cols);
unsigned *unchosen_row = XMALLOCNZ(unsigned, num_rows);
int *row_dec = XMALLOCNZ(int, num_rows);
int *col_inc = XMALLOCNZ(int, num_cols);
int *slack = XMALLOCNZ(int, num_cols);
unsigned *slack_row = XMALLOCNZ(unsigned, num_rows);
unsigned r;
unsigned c;
unsigned t;
......@@ -195,27 +192,27 @@ int hungarian_solve(hungarian_problem_t* p, unsigned *assignment,
memset(assignment, -1, num_rows * sizeof(assignment[0]));
/* Begin subtract column minima in order to start with lots of zeros 12 */
DBG((p->dbg, LEVEL_1, "Using heuristic\n"));
DBG((dbg, LEVEL_1, "Using heuristic\n"));
for (c = 0; c < num_cols; ++c) {
int s = p->cost[0][c];
unsigned col_mininum = cost[0*num_cols + c];
for (r = 1; r < num_rows; ++r) {
if (p->cost[r][c] < s)
s = p->cost[r][c];
if (cost[r*num_cols + c] < col_mininum)
col_mininum = cost[r*num_cols + c];
}
cost += s;
if (s == 0)
if (col_mininum == 0)
continue;
res_cost += col_mininum;
for (r = 0; r < num_rows; ++r)
p->cost[r][c] -= s;
cost[r*num_cols + c] -= col_mininum;
}
/* End subtract column minima in order to start with lots of zeros 12 */
/* Begin initial state 16 */
t = 0;
unmatched = 0;
for (c = 0; c < num_cols; ++c) {
row_mate[c] = (unsigned) -1;
parent_row[c] = (unsigned) -1;
......@@ -224,40 +221,43 @@ int hungarian_solve(hungarian_problem_t* p, unsigned *assignment,
}
for (r = 0; r < num_rows; ++r) {
int s = p->cost[r][0];
unsigned row_minimum = cost[r*num_cols + 0];
for (c = 1; c < num_cols; ++c) {
if (p->cost[r][c] < s)
s = p->cost[r][c];
if (cost[r*num_cols + c] < row_minimum)
row_minimum = cost[r*num_cols + c];
}
row_dec[r] = s;
row_dec[r] = row_minimum;
for (c = 0; c < num_cols; ++c) {
if (s == p->cost[r][c] && row_mate[c] == (unsigned)-1) {
col_mate[r] = c;
row_mate[c] = r;
DBG((p->dbg, LEVEL_1, "matching col %d == row %d\n", c, r));
goto row_done;
}
if (cost[r*num_cols + c] != row_minimum)
continue;
if (row_mate[c] != (unsigned)-1)
continue;
col_mate[r] = c;
row_mate[c] = r;
DBG((dbg, LEVEL_1, "matching col %u == row %u\n", c, r));
goto row_done;
}
col_mate[r] = (unsigned)-1;
DBG((p->dbg, LEVEL_1, "node %d: unmatched row %d\n", t, r));
unchosen_row[t++] = r;
DBG((dbg, LEVEL_1, "node %u: unmatched row %u\n", unmatched, r));
unchosen_row[unmatched++] = r;
row_done: ;
}
/* End initial state 16 */
/* Begin Hungarian algorithm 18 */
if (t == 0)
if (unmatched == 0)
goto done;
unmatched = t;
t = unmatched;
for (;;) {
unsigned q = 0;
unsigned j;
DBG((p->dbg, LEVEL_1, "Matched %d rows.\n", num_rows - t));
DBG((dbg, LEVEL_1, "Matched %u rows.\n", num_rows - t));
for (;;) {
int s;
......@@ -268,7 +268,7 @@ row_done: ;
for (c = 0; c < num_cols; ++c) {
if (slack[c]) {
int del = p->cost[r][c] - s + col_inc[c];
int del = cost[r*num_cols + c] - s + col_inc[c];
if (del < slack[c]) {
if (del == 0) {
......@@ -277,7 +277,7 @@ row_done: ;
slack[c] = 0;
parent_row[c] = r;
DBG((p->dbg, LEVEL_1, "node %d: row %d == col %d -- row %d\n", t, row_mate[c], c, r));
DBG((dbg, LEVEL_1, "node %u: row %u == col %u -- row %u\n", t, row_mate[c], c, r));
unchosen_row[t++] = row_mate[c];
} else {
slack[c] = del;
......@@ -306,7 +306,7 @@ row_done: ;
if (slack[c] == 0) {
/* Begin look at a new zero 22 */
r = slack_row[c];
DBG((p->dbg, LEVEL_1, "Decreasing uncovered elements by %d produces zero at [%d, %d]\n", s, r, c));
DBG((dbg, LEVEL_1, "Decreasing uncovered elements by %d produces zero at [%u, %u]\n", s, r, c));
if (row_mate[c] == (unsigned)-1) {
for (j = c + 1; j < num_cols; ++j) {
if (slack[j] == 0)
......@@ -315,7 +315,7 @@ row_done: ;
goto breakthru;
} else {
parent_row[c] = r;
DBG((p->dbg, LEVEL_1, "node %d: row %d == col %d -- row %d\n", t, row_mate[c], c, r));
DBG((dbg, LEVEL_1, "node %u: row %u == col %u -- row %u\n", t, row_mate[c], c, r));
unchosen_row[t++] = row_mate[c];
}
/* End look at a new zero 22 */
......@@ -328,13 +328,13 @@ row_done: ;
}
breakthru:
/* Begin update the matching 20 */
DBG((p->dbg, LEVEL_1, "Breakthrough at node %d of %d.\n", q, t));
DBG((dbg, LEVEL_1, "Breakthrough at node %u of %u.\n", q, t));
for (;;) {
j = col_mate[r];
col_mate[r] = c;
row_mate[c] = r;
DBG((p->dbg, LEVEL_1, "rematching col %d == row %d\n", c, r));
DBG((dbg, LEVEL_1, "rematching col %u == row %u\n", c, r));
if (j == (unsigned)-1)
break;
......@@ -349,13 +349,13 @@ breakthru:
/* Begin get ready for another stage 17 */
t = 0;
for (c = 0; c < num_cols; ++c) {
parent_row[c] = -1;
parent_row[c] = (unsigned) -1;
slack[c] = INT_MAX;
}
for (r = 0; r < num_rows; ++r) {
if (col_mate[r] == (unsigned)-1) {
DBG((p->dbg, LEVEL_1, "node %d: unmatched row %d\n", t, r));
DBG((dbg, LEVEL_1, "node %u: unmatched row %u\n", t, r));
unchosen_row[t++] = r;
}
}
......@@ -366,14 +366,15 @@ done:
/* Begin double check the solution 23 */
for (r = 0; r < num_rows; ++r) {
for (c = 0; c < num_cols; ++c) {
if (p->cost[r][c] < row_dec[r] - col_inc[c])
if ((int) cost[r*num_cols + c] < row_dec[r] - col_inc[c])
return -1;
}
}
for (r = 0; r < num_rows; ++r) {
c = col_mate[r];
if (c == (unsigned)-1 || p->cost[r][c] != row_dec[r] - col_inc[c])
if (c == (unsigned)-1
|| cost[r*num_cols + c] != (unsigned) (row_dec[r] - col_inc[c]))
return -2;
}
......@@ -390,7 +391,8 @@ done:
/* collect the assigned values */
for (r = 0; r < num_rows; ++r) {
if (cost_threshold > 0 && p->cost[r][col_mate[r]] >= cost_threshold)
if (cost_threshold > 0
&& cost[r*num_cols + col_mate[r]] >= cost_threshold)
assignment[r] = -1; /* remove matching having cost > threshold */
else
assignment[r] = col_mate[r];
......@@ -399,25 +401,25 @@ done:
/* In case of normal matching: remove impossible ones */
if (p->match_type == HUNGARIAN_MATCH_NORMAL) {
for (r = 0; r < num_rows; ++r) {
if (bitset_is_set(p->missing_left, r)
|| bitset_is_set(p->missing_right, col_mate[r]))
if (rbitset_is_set(p->missing_left, r)
|| rbitset_is_set(p->missing_right, col_mate[r]))
assignment[r] = -1;
}
}
for (r = 0; r < num_rows; ++r) {
for (c = 0; c < num_cols; ++c) {
p->cost[r][c] = p->cost[r][c] - row_dec[r] + col_inc[c];
cost[r*num_cols + c] = cost[r*num_cols + c] - row_dec[r] + col_inc[c];
}
}
for (r = 0; r < num_rows; ++r)
cost += row_dec[r];
res_cost += row_dec[r];
for (c = 0; c < num_cols; ++c)
cost -= col_inc[c];
res_cost -= col_inc[c];
DBG((p->dbg, LEVEL_1, "Cost is %d\n", cost));
DBG((dbg, LEVEL_1, "Cost is %d\n", res_cost));
xfree(slack);
xfree(col_inc);
......@@ -429,7 +431,7 @@ done:
xfree(col_mate);
if (final_cost != NULL)
*final_cost = cost;
*final_cost = res_cost;
return 0;
}
......@@ -1495,7 +1495,8 @@ static ir_nodeset_t *compute_maximal_antichain(rss_t *rss, dvg_t *dvg, int itera
ir_nodeset_iterator_t iter;
ir_node *u_irn;
unsigned i, j;
int cost, cur_chain, res;
unsigned cost;
int cur_chain, res;
rss_edge_t *dvg_edge;
#define MAP_IDX(irn) bsearch_for_index(get_irn_idx(irn), idx_map, n, 1)
......@@ -1595,8 +1596,8 @@ static ir_nodeset_t *compute_maximal_antichain(rss_t *rss, dvg_t *dvg, int itera
}
}
DBG((rss->dbg, LEVEL_2, "\t\tgot assignment with cost %d\n", cost));
DBG((rss->dbg, LEVEL_3, "\t\t\tassignment --- reverse assignment\n", cost));
DBG((rss->dbg, LEVEL_2, "\t\tgot assignment with cost %u\n", cost));
DBG((rss->dbg, LEVEL_3, "\t\t\tassignment --- reverse assignment\n"));
for (i = 0; i < n; ++i) {
DBG((rss->dbg, LEVEL_3, "\t\t\t%3u -> %3u %3u -> %3u\n", i, assignment[i], i, assignment_rev[i]));
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment