sparse-index: expand_to_path()
[git] / linear-assignment.c
1 /*
2  * Based on: Jonker, R., & Volgenant, A. (1987). <i>A shortest augmenting path
3  * algorithm for dense and sparse linear assignment problems</i>. Computing,
4  * 38(4), 325-340.
5  */
6 #include "cache.h"
7 #include "linear-assignment.h"
8
9 #define COST(column, row) cost[(column) + column_count * (row)]
10
11 /*
12  * The parameter `cost` is the cost matrix: the cost to assign column j to row
13  * i is `cost[j + column_count * i].
14  */
15 void compute_assignment(int column_count, int row_count, int *cost,
16                         int *column2row, int *row2column)
17 {
18         int *v, *d;
19         int *free_row, free_count = 0, saved_free_count, *pred, *col;
20         int i, j, phase;
21
22         if (column_count < 2) {
23                 memset(column2row, 0, sizeof(int) * column_count);
24                 memset(row2column, 0, sizeof(int) * row_count);
25                 return;
26         }
27
28         memset(column2row, -1, sizeof(int) * column_count);
29         memset(row2column, -1, sizeof(int) * row_count);
30         ALLOC_ARRAY(v, column_count);
31
32         /* column reduction */
33         for (j = column_count - 1; j >= 0; j--) {
34                 int i1 = 0;
35
36                 for (i = 1; i < row_count; i++)
37                         if (COST(j, i1) > COST(j, i))
38                                 i1 = i;
39                 v[j] = COST(j, i1);
40                 if (row2column[i1] == -1) {
41                         /* row i1 unassigned */
42                         row2column[i1] = j;
43                         column2row[j] = i1;
44                 } else {
45                         if (row2column[i1] >= 0)
46                                 row2column[i1] = -2 - row2column[i1];
47                         column2row[j] = -1;
48                 }
49         }
50
51         /* reduction transfer */
52         ALLOC_ARRAY(free_row, row_count);
53         for (i = 0; i < row_count; i++) {
54                 int j1 = row2column[i];
55                 if (j1 == -1)
56                         free_row[free_count++] = i;
57                 else if (j1 < -1)
58                         row2column[i] = -2 - j1;
59                 else {
60                         int min = COST(!j1, i) - v[!j1];
61                         for (j = 1; j < column_count; j++)
62                                 if (j != j1 && min > COST(j, i) - v[j])
63                                         min = COST(j, i) - v[j];
64                         v[j1] -= min;
65                 }
66         }
67
68         if (free_count ==
69             (column_count < row_count ? row_count - column_count : 0)) {
70                 free(v);
71                 free(free_row);
72                 return;
73         }
74
75         /* augmenting row reduction */
76         for (phase = 0; phase < 2; phase++) {
77                 int k = 0;
78
79                 saved_free_count = free_count;
80                 free_count = 0;
81                 while (k < saved_free_count) {
82                         int u1, u2;
83                         int j1 = 0, j2, i0;
84
85                         i = free_row[k++];
86                         u1 = COST(j1, i) - v[j1];
87                         j2 = -1;
88                         u2 = INT_MAX;
89                         for (j = 1; j < column_count; j++) {
90                                 int c = COST(j, i) - v[j];
91                                 if (u2 > c) {
92                                         if (u1 < c) {
93                                                 u2 = c;
94                                                 j2 = j;
95                                         } else {
96                                                 u2 = u1;
97                                                 u1 = c;
98                                                 j2 = j1;
99                                                 j1 = j;
100                                         }
101                                 }
102                         }
103                         if (j2 < 0) {
104                                 j2 = j1;
105                                 u2 = u1;
106                         }
107
108                         i0 = column2row[j1];
109                         if (u1 < u2)
110                                 v[j1] -= u2 - u1;
111                         else if (i0 >= 0) {
112                                 j1 = j2;
113                                 i0 = column2row[j1];
114                         }
115
116                         if (i0 >= 0) {
117                                 if (u1 < u2)
118                                         free_row[--k] = i0;
119                                 else
120                                         free_row[free_count++] = i0;
121                         }
122                         row2column[i] = j1;
123                         column2row[j1] = i;
124                 }
125         }
126
127         /* augmentation */
128         saved_free_count = free_count;
129         ALLOC_ARRAY(d, column_count);
130         ALLOC_ARRAY(pred, column_count);
131         ALLOC_ARRAY(col, column_count);
132         for (free_count = 0; free_count < saved_free_count; free_count++) {
133                 int i1 = free_row[free_count], low = 0, up = 0, last, k;
134                 int min, c, u1;
135
136                 for (j = 0; j < column_count; j++) {
137                         d[j] = COST(j, i1) - v[j];
138                         pred[j] = i1;
139                         col[j] = j;
140                 }
141
142                 j = -1;
143                 do {
144                         last = low;
145                         min = d[col[up++]];
146                         for (k = up; k < column_count; k++) {
147                                 j = col[k];
148                                 c = d[j];
149                                 if (c <= min) {
150                                         if (c < min) {
151                                                 up = low;
152                                                 min = c;
153                                         }
154                                         col[k] = col[up];
155                                         col[up++] = j;
156                                 }
157                         }
158                         for (k = low; k < up; k++)
159                                 if (column2row[col[k]] == -1)
160                                         goto update;
161
162                         /* scan a row */
163                         do {
164                                 int j1 = col[low++];
165
166                                 i = column2row[j1];
167                                 u1 = COST(j1, i) - v[j1] - min;
168                                 for (k = up; k < column_count; k++) {
169                                         j = col[k];
170                                         c = COST(j, i) - v[j] - u1;
171                                         if (c < d[j]) {
172                                                 d[j] = c;
173                                                 pred[j] = i;
174                                                 if (c == min) {
175                                                         if (column2row[j] == -1)
176                                                                 goto update;
177                                                         col[k] = col[up];
178                                                         col[up++] = j;
179                                                 }
180                                         }
181                                 }
182                         } while (low != up);
183                 } while (low == up);
184
185 update:
186                 /* updating of the column pieces */
187                 for (k = 0; k < last; k++) {
188                         int j1 = col[k];
189                         v[j1] += d[j1] - min;
190                 }
191
192                 /* augmentation */
193                 do {
194                         if (j < 0)
195                                 BUG("negative j: %d", j);
196                         i = pred[j];
197                         column2row[j] = i;
198                         SWAP(j, row2column[i]);
199                 } while (i1 != i);
200         }
201
202         free(col);
203         free(pred);
204         free(d);
205         free(v);
206         free(free_row);
207 }