summaryrefslogtreecommitdiff
path: root/src/match.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/match.c')
-rw-r--r--src/match.c392
1 files changed, 392 insertions, 0 deletions
diff --git a/src/match.c b/src/match.c
new file mode 100644
index 0000000..1b3700c
--- /dev/null
+++ b/src/match.c
@@ -0,0 +1,392 @@
1/*****************************************************************************
2 *
3 * mtdev - MT device event converter (MIT license)
4 *
5 * Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se>
6 * Copyright (C) 2010 Canonical Ltd.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the next
16 * paragraph) shall be included in all copies or substantial portions of the
17 * Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
26 *
27 ****************************************************************************/
28
29#include "match.h"
30#include <string.h>
31#include <stdio.h>
32
33/**
34 * Bitmap implementation of the hungarian algorithm (GPL license)
35 *
36 * Copyright (C) 2008 Henrik Rydberg <rydberg@euromail.se>
37 *
38 * Based on code released by Markus Buehren (2004) (BSD license)
39 *
40 * Copyright (C) 2004, Markus Buehren. All rights reserved.
41 * See CREDITS file for full license terms.
42 *
43 */
44
45typedef unsigned col_t[1];
46typedef unsigned mat_t[DIM_FINGER];
47
48#define GET1(m, x) ((m[0] >> (x)) & 1U)
49#define SET1(m, x) (m[0] |= (1U << (x)))
50#define CLEAR1(m, x) (m[0] &= ~(1U << (x)))
51
52#define GET2(m, row, col) ((m[col] >> (row)) & 1U)
53#define SET2(m, row, col) (m[col] |= (1U << (row)))
54#define CLEAR2(m, row, col) (m[col] &= ~(1U << (row)))
55
56/********************************************************/
57
58static void buildixvector(int *ix, mat_t mstar, int nrows, int ncols)
59{
60 int row, col;
61 for (row = 0; row < nrows; row++) {
62 for (col = 0; col < ncols; col++) {
63 if (GET2(mstar, row, col)) {
64 ix[row] = col;
65 break;
66 }
67 }
68 }
69}
70
71
72/********************************************************/
73
74static void step2a(int *ix, int *mdist, mat_t mstar, mat_t nmstar,
75 mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols,
76 int dmin);
77static void step2b(int *ix, int *mdist, mat_t mstar, mat_t nmstar,
78 mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols,
79 int dmin);
80static void step3(int *ix, int *mdist, mat_t mstar, mat_t nmstar,
81 mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols,
82 int dmin);
83static void step4(int *ix, int *mdist, mat_t mstar, mat_t nmstar,
84 mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols,
85 int dmin, int row, int col);
86static void step5(int *ix, int *mdist, mat_t mstar, mat_t nmstar,
87 mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols,
88 int dmin);
89
90static void ixoptimal(int *ix, int *mdist, int nrows, int ncols)
91{
92 int *mdistTemp, *mdistEnd, *columnEnd, value, minValue;
93 int dmin, row, col;
94 col_t ccol, crow;
95 mat_t mstar, mprime, nmstar;
96
97 memset(ccol, 0, sizeof(col_t));
98 memset(crow, 0, sizeof(col_t));
99 memset(mstar, 0, sizeof(mat_t));
100 memset(mprime, 0, sizeof(mat_t));
101 memset(nmstar, 0, sizeof(mat_t));
102
103 /* initialization */
104 for (row = 0; row < nrows; row++)
105 ix[row] = -1;
106
107 mdistEnd = mdist + nrows * ncols;
108
109 /* preliminary steps */
110 if (nrows <= ncols) {
111 dmin = nrows;
112
113 for (row = 0; row < nrows; row++) {
114 /* find the smallest element in the row */
115 mdistTemp = mdist + row;
116 minValue = *mdistTemp;
117 mdistTemp += nrows;
118 while (mdistTemp < mdistEnd) {
119 value = *mdistTemp;
120 if (value < minValue)
121 minValue = value;
122 mdistTemp += nrows;
123 }
124
125 /* subtract the smallest element from each element
126 of the row */
127 mdistTemp = mdist + row;
128 while (mdistTemp < mdistEnd) {
129 *mdistTemp -= minValue;
130 mdistTemp += nrows;
131 }
132 }
133
134 /* Steps 1 and 2a */
135 for (row = 0; row < nrows; row++) {
136 for (col = 0; col < ncols; col++) {
137 if (mdist[row + nrows * col] != 0)
138 continue;
139 if (GET1(ccol, col))
140 continue;
141 SET2(mstar, row, col);
142 SET1(ccol, col);
143 break;
144 }
145 }
146 } else {
147 dmin = ncols;
148
149 for (col = 0; col < ncols; col++) {
150 /* find the smallest element in the column */
151 mdistTemp = mdist + nrows*col;
152 columnEnd = mdistTemp + nrows;
153
154 minValue = *mdistTemp++;
155 while (mdistTemp < columnEnd) {
156 value = *mdistTemp++;
157 if (value < minValue)
158 minValue = value;
159 }
160
161 /* subtract the smallest element from each element
162 of the column */
163 mdistTemp = mdist + nrows*col;
164 while (mdistTemp < columnEnd)
165 *mdistTemp++ -= minValue;
166 }
167
168 /* Steps 1 and 2a */
169 for (col = 0; col < ncols; col++) {
170 for (row = 0; row < nrows; row++) {
171 if (mdist[row + nrows * col] != 0)
172 continue;
173 if (GET1(crow, row))
174 continue;
175 SET2(mstar, row, col);
176 SET1(ccol, col);
177 SET1(crow, row);
178 break;
179 }
180 }
181 memset(crow, 0, sizeof(col_t));
182 }
183
184 /* move to step 2b */
185 step2b(ix, mdist, mstar, nmstar,
186 mprime, ccol, crow, nrows, ncols,
187 dmin);
188}
189
190/********************************************************/
191static void step2a(int *ix, int *mdist, mat_t mstar, mat_t nmstar,
192 mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols,
193 int dmin)
194{
195 int col, row;
196
197 /* cover every column containing a starred zero */
198 for (col = 0; col < ncols; col++) {
199 for (row = 0; row < nrows; row++) {
200 if (!GET2(mstar, row, col))
201 continue;
202 SET1(ccol, col);
203 break;
204 }
205 }
206
207 /* move to step 3 */
208 step2b(ix, mdist, mstar, nmstar,
209 mprime, ccol, crow, nrows, ncols,
210 dmin);
211}
212
213/********************************************************/
214static void step2b(int *ix, int *mdist, mat_t mstar, mat_t nmstar,
215 mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols,
216 int dmin)
217{
218 int col, ncc;
219
220 /* count covered columns */
221 ncc = 0;
222 for (col = 0; col < ncols; col++)
223 if (GET1(ccol, col))
224 ncc++;
225
226 if (ncc == dmin) {
227 /* algorithm finished */
228 buildixvector(ix, mstar, nrows, ncols);
229 } else {
230 /* move to step 3 */
231 step3(ix, mdist, mstar, nmstar,
232 mprime, ccol, crow, nrows, ncols,
233 dmin);
234 }
235
236}
237
238/********************************************************/
239static void step3(int *ix, int *mdist, mat_t mstar, mat_t nmstar,
240 mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols,
241 int dmin)
242{
243 int zerosFound;
244 int row, col, cstar;
245
246 zerosFound = 1;
247 while (zerosFound) {
248 zerosFound = 0;
249 for (col = 0; col < ncols; col++) {
250 if (GET1(ccol, col))
251 continue;
252 for (row = 0; row < nrows; row++) {
253 if (mdist[row + nrows * col] != 0)
254 continue;
255 if (GET1(crow, row))
256 continue;
257
258 /* prime zero */
259 SET2(mprime, row, col);
260
261 /* find starred zero in current row */
262 for (cstar = 0; cstar < ncols; cstar++)
263 if (GET2(mstar, row, cstar))
264 break;
265
266 if (cstar == ncols) { /* no starred zero */
267 /* move to step 4 */
268 step4(ix, mdist, mstar, nmstar,
269 mprime, ccol, crow, nrows, ncols,
270 dmin, row, col);
271 return;
272 } else {
273 SET1(crow, row);
274 CLEAR1(ccol, cstar);
275 zerosFound = 1;
276 break;
277 }
278 }
279 }
280 }
281
282 /* move to step 5 */
283 step5(ix, mdist, mstar, nmstar,
284 mprime, ccol, crow, nrows, ncols,
285 dmin);
286}
287
288/********************************************************/
289static void step4(int *ix, int *mdist, mat_t mstar, mat_t nmstar,
290 mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols,
291 int dmin, int row, int col)
292{
293 int n, rstar, cstar, primeRow, primeCol;
294
295 /* generate temporary copy of mstar */
296 memcpy(nmstar, mstar, sizeof(mat_t));
297
298 /* star current zero */
299 SET2(nmstar, row, col);
300
301 /* find starred zero in current column */
302 cstar = col;
303 for (rstar = 0; rstar < nrows; rstar++)
304 if (GET2(mstar, rstar, cstar))
305 break;
306
307 while (rstar < nrows) {
308 /* unstar the starred zero */
309 CLEAR2(nmstar, rstar, cstar);
310
311 /* find primed zero in current row */
312 primeRow = rstar;
313 for (primeCol = 0; primeCol < ncols; primeCol++)
314 if (GET2(mprime, primeRow, primeCol))
315 break;
316
317 /* star the primed zero */
318 SET2(nmstar, primeRow, primeCol);
319
320 /* find starred zero in current column */
321 cstar = primeCol;
322 for (rstar = 0; rstar < nrows; rstar++)
323 if (GET2(mstar, rstar, cstar))
324 break;
325 }
326
327 /* use temporary copy as new mstar */
328 /* delete all primes, uncover all rows */
329 memcpy(mstar, nmstar, sizeof(mat_t));
330 memset(mprime, 0, sizeof(mat_t));
331 memset(crow, 0, sizeof(col_t));
332
333 /* move to step 2a */
334 step2a(ix, mdist, mstar, nmstar,
335 mprime, ccol, crow, nrows, ncols,
336 dmin);
337}
338
339/********************************************************/
340static void step5(int *ix, int *mdist, mat_t mstar, mat_t nmstar,
341 mat_t mprime, col_t ccol, col_t crow, int nrows, int ncols,
342 int dmin)
343{
344 int h = 0, value;
345 int row, col, found = 0;
346
347 /* find smallest uncovered element h */
348 for (row = 0; row < nrows; row++) {
349 if (GET1(crow, row))
350 continue;
351 for (col = 0; col < ncols; col++) {
352 if (GET1(ccol, col))
353 continue;
354 value = mdist[row + nrows * col];
355 if (!found || value < h) {
356 h = value;
357 found = 1;
358 }
359 }
360 }
361
362 /* where to go if nothing uncovered? */
363 if (!found)
364 return;
365
366 /* add h to each covered row */
367 for (row = 0; row < nrows; row++) {
368 if (!GET1(crow, row))
369 continue;
370 for (col = 0; col < ncols; col++)
371 mdist[row + nrows * col] += h;
372 }
373
374 /* subtract h from each uncovered column */
375 for (col = 0; col < ncols; col++) {
376 if (GET1(ccol, col))
377 continue;
378 for (row = 0; row < nrows; row++)
379 mdist[row + nrows * col] -= h;
380 }
381
382 /* move to step 3 */
383 step3(ix, mdist, mstar, nmstar,
384 mprime, ccol, crow, nrows, ncols,
385 dmin);
386}
387
388void match_fingers(int ix[DIM_FINGER], int A[DIM2_FINGER], int nrow, int ncol)
389{
390 ixoptimal(ix, A, nrow, ncol);
391}
392