matching.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /*
  2. * Implementation of matching.h.
  3. */
  4. #include <assert.h>
  5. #include <stdlib.h>
  6. #include <stdio.h>
  7. #include "puzzles.h"
  8. #include "matching.h"
  9. struct scratch {
  10. /*
  11. * Current contents of the in-progress matching. LtoR is an array
  12. * of nl integers, each of which holds a value in {0,1,...,nr-1},
  13. * or -1 for no current assignment. RtoL is exactly the reverse.
  14. *
  15. * Invariant: LtoR[i] is non-empty and equal to j if and only if
  16. * RtoL[j] is non-empty and equal to i.
  17. */
  18. int *LtoR, *RtoL;
  19. /*
  20. * Arrays of nl and nr integer respectively, giving the layer
  21. * assigned to each integer in the breadth-first search step of
  22. * the algorithm.
  23. */
  24. int *Llayer, *Rlayer;
  25. /*
  26. * Arrays of nl and nr integers respectively, used to hold the
  27. * to-do queues in the breadth-first search.
  28. */
  29. int *Lqueue, *Rqueue;
  30. /*
  31. * An augmenting path of vertices, alternating between L vertices
  32. * (in the even-numbered positions, starting at 0) and R (in the
  33. * odd positions). Must be long enough to hold any such path that
  34. * never repeats a vertex, i.e. must be at least 2*min(nl,nr) in
  35. * size.
  36. */
  37. int *augpath;
  38. /*
  39. * Track the progress of the depth-first search at each
  40. * even-numbered layer. Has one element for each even-numbered
  41. * position in augpath.
  42. */
  43. int *dfsstate;
  44. /*
  45. * Store a random permutation of the L vertex indices, if we're
  46. * randomising the dfs phase.
  47. */
  48. int *Lorder;
  49. };
  50. size_t matching_scratch_size(int nl, int nr)
  51. {
  52. size_t n;
  53. int nmin = (nl < nr ? nl : nr);
  54. n = (sizeof(struct scratch) + sizeof(int)-1)/sizeof(int);
  55. n += nl; /* LtoR */
  56. n += nr; /* RtoL */
  57. n += nl; /* Llayer */
  58. n += nr; /* Rlayer */
  59. n += nl; /* Lqueue */
  60. n += nr; /* Rqueue */
  61. n += 2*nmin; /* augpath */
  62. n += nmin; /* dfsstate */
  63. n += nl; /* Lorder */
  64. return n * sizeof(int);
  65. }
  66. int matching_with_scratch(void *scratchv,
  67. int nl, int nr, int **adjlists, int *adjsizes,
  68. random_state *rs, int *outl, int *outr)
  69. {
  70. struct scratch *s = (struct scratch *)scratchv;
  71. int L, R, i, j;
  72. /*
  73. * Set up the various array pointers in the scratch space.
  74. */
  75. {
  76. int *p = scratchv;
  77. int nmin = (nl < nr ? nl : nr);
  78. p += (sizeof(struct scratch) + sizeof(int)-1)/sizeof(int);
  79. s->LtoR = p; p += nl;
  80. s->RtoL = p; p += nr;
  81. s->Llayer = p; p += nl;
  82. s->Rlayer = p; p += nr;
  83. s->Lqueue = p; p += nl;
  84. s->Rqueue = p; p += nr;
  85. s->augpath = p; p += 2*nmin;
  86. s->dfsstate = p; p += nmin;
  87. s->Lorder = p; p += nl;
  88. }
  89. /*
  90. * Set up the initial matching, which is empty.
  91. */
  92. for (L = 0; L < nl; L++)
  93. s->LtoR[L] = -1;
  94. for (R = 0; R < nr; R++)
  95. s->RtoL[R] = -1;
  96. while (1) {
  97. /*
  98. * Breadth-first search starting from the unassigned left
  99. * vertices, traversing edges from left to right only if they
  100. * are _not_ part of the matching, and from right to left only
  101. * if they _are_. We assign a 'layer number' to all vertices
  102. * visited by this search, with the starting vertices being
  103. * layer 0 and every successor of a layer-n node being layer
  104. * n+1.
  105. */
  106. int Lqs, Rqs, layer, target_layer;
  107. for (L = 0; L < nl; L++)
  108. s->Llayer[L] = -1;
  109. for (R = 0; R < nr; R++)
  110. s->Rlayer[R] = -1;
  111. Lqs = 0;
  112. for (L = 0; L < nl; L++) {
  113. if (s->LtoR[L] == -1) {
  114. s->Llayer[L] = 0;
  115. s->Lqueue[Lqs++] = L;
  116. }
  117. }
  118. layer = 0;
  119. while (1) {
  120. bool found_free_R_vertex = false;
  121. Rqs = 0;
  122. for (i = 0; i < Lqs; i++) {
  123. L = s->Lqueue[i];
  124. assert(s->Llayer[L] == layer);
  125. for (j = 0; j < adjsizes[L]; j++) {
  126. R = adjlists[L][j];
  127. if (R != s->LtoR[L] && s->Rlayer[R] == -1) {
  128. s->Rlayer[R] = layer+1;
  129. s->Rqueue[Rqs++] = R;
  130. if (s->RtoL[R] == -1)
  131. found_free_R_vertex = true;
  132. }
  133. }
  134. }
  135. layer++;
  136. if (found_free_R_vertex)
  137. break;
  138. if (Rqs == 0)
  139. goto done;
  140. Lqs = 0;
  141. for (j = 0; j < Rqs; j++) {
  142. R = s->Rqueue[j];
  143. assert(s->Rlayer[R] == layer);
  144. if ((L = s->RtoL[R]) != -1 && s->Llayer[L] == -1) {
  145. s->Llayer[L] = layer+1;
  146. s->Lqueue[Lqs++] = L;
  147. }
  148. }
  149. layer++;
  150. if (Lqs == 0)
  151. goto done;
  152. }
  153. target_layer = layer;
  154. /*
  155. * Vertices in the target layer are only interesting if
  156. * they're actually unassigned. Blanking out the others here
  157. * will save us a special case in the dfs loop below.
  158. */
  159. for (R = 0; R < nr; R++)
  160. if (s->Rlayer[R] == target_layer && s->RtoL[R] != -1)
  161. s->Rlayer[R] = -1;
  162. /*
  163. * Choose an ordering in which to try the L vertices at the
  164. * start of the next pass.
  165. */
  166. for (L = 0; L < nl; L++)
  167. s->Lorder[L] = L;
  168. if (rs)
  169. shuffle(s->Lorder, nl, sizeof(*s->Lorder), rs);
  170. /*
  171. * Now depth-first search through that layered set of vertices
  172. * to find as many (vertex-)disjoint augmenting paths as we
  173. * can, and for each one we find, augment the matching.
  174. */
  175. s->dfsstate[0] = 0;
  176. i = 0;
  177. while (1) {
  178. /*
  179. * Find the next vertex to go on the end of augpath.
  180. */
  181. if (i == 0) {
  182. /* In this special case, we're just looking for L
  183. * vertices that are not yet assigned. */
  184. if (s->dfsstate[i] == nl)
  185. break; /* entire DFS has finished */
  186. L = s->Lorder[s->dfsstate[i]++];
  187. if (s->Llayer[L] != 2*i)
  188. continue; /* skip this vertex */
  189. } else {
  190. /* In the more usual case, we're going through the
  191. * adjacency list for the previous L vertex. */
  192. L = s->augpath[2*i-2];
  193. j = s->dfsstate[i]++;
  194. if (j == adjsizes[L]) {
  195. /* Run out of neighbours of the previous vertex. */
  196. i--;
  197. continue;
  198. }
  199. if (rs && adjsizes[L] - j > 1) {
  200. int which = j + random_upto(rs, adjsizes[L] - j);
  201. int tmp = adjlists[L][which];
  202. adjlists[L][which] = adjlists[L][j];
  203. adjlists[L][j] = tmp;
  204. }
  205. R = adjlists[L][j];
  206. if (s->Rlayer[R] != 2*i-1)
  207. continue; /* skip this vertex */
  208. s->augpath[2*i-1] = R;
  209. s->Rlayer[R] = -1; /* mark vertex as visited */
  210. if (2*i-1 == target_layer) {
  211. /*
  212. * We've found an augmenting path, in the form of
  213. * an even-sized list of vertices alternating
  214. * L,R,...,L,R, with the initial L and final R
  215. * vertex free and otherwise each R currently
  216. * connected to the next L. Adjust so that each L
  217. * connects to the next R, increasing the edge
  218. * count in the matching by 1.
  219. */
  220. for (j = 0; j < 2*i; j += 2) {
  221. s->LtoR[s->augpath[j]] = s->augpath[j+1];
  222. s->RtoL[s->augpath[j+1]] = s->augpath[j];
  223. }
  224. /*
  225. * Having dealt with that path, and already marked
  226. * all its vertices as visited, rewind right to
  227. * the start and resume our DFS from a new
  228. * starting L-vertex.
  229. */
  230. i = 0;
  231. continue;
  232. }
  233. L = s->RtoL[R];
  234. if (s->Llayer[L] != 2*i)
  235. continue; /* skip this vertex */
  236. }
  237. s->augpath[2*i] = L;
  238. s->Llayer[L] = -1; /* mark vertex as visited */
  239. i++;
  240. s->dfsstate[i] = 0;
  241. }
  242. }
  243. done:
  244. /*
  245. * Fill in the output arrays.
  246. */
  247. if (outl) {
  248. for (i = 0; i < nl; i++)
  249. outl[i] = s->LtoR[i];
  250. }
  251. if (outr) {
  252. for (j = 0; j < nr; j++)
  253. outr[j] = s->RtoL[j];
  254. }
  255. /*
  256. * Return the number of matching edges.
  257. */
  258. for (i = j = 0; i < nl; i++)
  259. if (s->LtoR[i] != -1)
  260. j++;
  261. return j;
  262. }
  263. int matching(int nl, int nr, int **adjlists, int *adjsizes,
  264. random_state *rs, int *outl, int *outr)
  265. {
  266. void *scratch;
  267. int size;
  268. int ret;
  269. size = matching_scratch_size(nl, nr);
  270. scratch = malloc(size);
  271. if (!scratch)
  272. return -1;
  273. ret = matching_with_scratch(scratch, nl, nr, adjlists, adjsizes,
  274. rs, outl, outr);
  275. free(scratch);
  276. return ret;
  277. }
  278. void matching_witness(void *scratchv, int nl, int nr, int *witness)
  279. {
  280. struct scratch *s = (struct scratch *)scratchv;
  281. int i, j;
  282. for (i = 0; i < nl; i++)
  283. witness[i] = s->Llayer[i] == -1;
  284. for (j = 0; j < nr; j++)
  285. witness[nl + j] = s->Rlayer[j] == -1;
  286. }