Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

334 lines
10 KiB

  1. /******************************************************************************
  2. *
  3. * LHMatch BFS
  4. *
  5. * Authors: Nicholas Harvey and Laszlo Lovasz
  6. *
  7. * Developed: Nov 2000 - June 2001
  8. *
  9. * Algorithm Description:
  10. *
  11. * The theoretical description of this algorithm is fairly complicated and
  12. * will not be given here.
  13. *
  14. * Runtime:
  15. *
  16. * Assume that the input graph is G=(U \union V, E) where U is the set of
  17. * left-hand vertices and V is the set of right-hand vertices. Then the
  18. * worst-case runtime of this algorithm is O(|V|^1.5 * |E|), but in practice
  19. * the algorithm is quite fast.
  20. *
  21. * Implementation details which improve performance:
  22. *
  23. * - Right-hand vertices are stored in buckets containing doubly-linked lists
  24. * for quick iteration and update.
  25. * - After a full pass of the graph, only the Queue contents are unmarked.
  26. * - Search from Low-load Vertices for High-load Vertices
  27. * - Check the degree of RHS vertices when enqueuing them
  28. * - After augmenting, continue searching among unmarked vertices.
  29. * - When computing the greedy matching, consider LHS vertices in order of
  30. * increasing degree.
  31. * - Force inline of key functions in inner loop
  32. * - Update gMaxRHSLoad after each iteration.
  33. *
  34. ******************************************************************************/
  35. /***** Header Files *****/
  36. #include <stdio.h>
  37. #include <stdlib.h>
  38. #include <string.h>
  39. #include <assert.h>
  40. #include "LHMatchInt.h"
  41. /***** InitializeBFS *****/
  42. /* Inititalize BFS: Clear parent pointers, allocate queue */
  43. static int InitializeBFS(Graph *g) {
  44. int i;
  45. /* Clear the parent pointers */
  46. for(i=0;i<g->numLHSVtx;i++) g->lVtx[i].parent=NULL;
  47. for(i=0;i<g->numRHSVtx;i++) g->rVtx[i].parent=NULL;
  48. return InitializeQueue(g);
  49. }
  50. /***** AddVtxToTree *****/
  51. /* Add vertex v to the queue and to the BFS tree with parent p */
  52. static __forceinline void AddVtxToTree(Graph *g, Vertex *v, Vertex *p) {
  53. DPRINT( printf("Adding %d to queue with parent %d\n",v->id,p->id); )
  54. v->parent = p;
  55. g->Queue[g->Qsize++] = v;
  56. }
  57. /***** UpdateNegPath *****/
  58. /* Found an neg-cost alternating path. Switch the matching edges
  59. * along it, causing the number of matching edges at the endpoints
  60. * to change. We update the endpoints' positions in the ordering. */
  61. static void UpdateNegPath(Graph *g, Vertex *u, Vertex *v) {
  62. Vertex *p,*w;
  63. DPRINT( printf("Low Endpoint: %d. Increase load to %d\n",
  64. u->id, u->numMatched+1 ); )
  65. DPRINT( printf("High Endpoint: %d. Decrease load to %d\n",
  66. v->id, v->numMatched-1 ); )
  67. assert( u->numMatched <= v->numMatched-2 );
  68. /* Switch along the path */
  69. w=v;
  70. do {
  71. assert( !IS_LHS_VTX(w) );
  72. p=w->parent;
  73. assert( IS_LHS_VTX(p) );
  74. w=p->parent;
  75. p->matchedWith=w;
  76. #ifdef STATS
  77. g->stats.TotalAugpathLen+=2;
  78. #endif
  79. } while(w!=u);
  80. /* Move vertex u into the next highest bucket */
  81. RemoveVtxFromBucket(g,u,u->numMatched);
  82. u->numMatched++;
  83. AddVtxToBucket(g,u,u->numMatched);
  84. /* Move vertex v into the next lowest bucket */
  85. RemoveVtxFromBucket(g,v,v->numMatched);
  86. v->numMatched--;
  87. AddVtxToBucket(g,v,v->numMatched);
  88. }
  89. /***** PrintStats *****/
  90. static void PrintStats(Graph* g) {
  91. #ifdef STATS
  92. int i,m=0,vzd=0,mrv=0,trmd=0,cost=0;
  93. for(i=0;i<g->numLHSVtx;i++) {
  94. m+=g->lVtx[i].degree;
  95. if(g->lVtx[i].degree==0) vzd++;
  96. }
  97. for(i=0;i<g->numRHSVtx;i++) {
  98. if(g->rVtx[i].numMatched>0) mrv++;
  99. trmd+=g->rVtx[i].numMatched;
  100. cost+=g->rVtx[i].numMatched*(g->rVtx[i].numMatched+1)/2;
  101. }
  102. printf("##### GRAPH STATISTICS #####\n");
  103. printf("|LHS|=%d, |RHS|=%d\n",g->numLHSVtx,g->numRHSVtx);
  104. printf("Total # vertices: %d, Total # edges: %d\n",
  105. g->numLHSVtx+g->numRHSVtx, m);
  106. printf("# LHS vertices with degree 0: %d\n",vzd);
  107. printf("Total M-degree of RHS vertices (should = |LHS|): %d\n",trmd);
  108. printf("Total matching cost: %d\n",cost);
  109. printf("# RHS vertices with M-degree > 0 (Max Matching): %d\n",mrv);
  110. printf("\n##### ALGORITHM STATISTICS #####\n");
  111. printf("Total # Augmentations: %d\n", g->stats.TotalAugs);
  112. printf("Avg length of augmenting path: %.2lf\n",
  113. g->stats.TotalAugs
  114. ? ((double)g->stats.TotalAugpathLen)/(double)g->stats.TotalAugs
  115. : 0. );
  116. printf("Total number of BFS trees grown: %d\n", g->stats.TotalBFSTrees);
  117. printf("Avg Size of Augmenting BFS Tree: %.2lf\n",
  118. g->stats.TotalAugs
  119. ? ((double)g->stats.TotalAugBFSTreeSize)/(double)g->stats.TotalAugs
  120. : 0. );
  121. printf("Total number of restarts (passes over RHS): %d\n",
  122. g->stats.TotalRestarts);
  123. #endif
  124. }
  125. /***** DoBFS *****/
  126. /* Add u to the queue and start a BFS from vertex u.
  127. * If an augmenting path was found return m, the end of the augmenting path.
  128. * If no path was found, return NULL. */
  129. static __forceinline Vertex* DoBFS( Graph *g, Vertex *u ) {
  130. Vertex *v, *n, *m;
  131. int q, j;
  132. /* Start a BFS from u: add u to the queue */
  133. DPRINT( printf("Using as root\n"); )
  134. u->parent=u;
  135. q = g->Qsize;
  136. g->Queue[g->Qsize++]=u;
  137. #ifdef STATS
  138. g->stats.TotalBFSTrees++;
  139. #endif
  140. /* Process the vertices in the queue */
  141. for(; q<g->Qsize; q++ ) {
  142. v = g->Queue[q];
  143. DPRINT( printf("Dequeued %d\n",v->id); )
  144. if(IS_LHS_VTX(v)) {
  145. /* The LHS vertices are only in the queue so that we
  146. * can keep track of which vertices have been marked. */
  147. continue;
  148. }
  149. /* Examine each of v's neighbours */
  150. for( j=0; j<v->degree; j++ ) {
  151. /* Examine neighbour n */
  152. n = v->adjList[j];
  153. assert(IS_LHS_VTX(n));
  154. if(n->matchedWith==v) {
  155. continue; /* Can't add flow to v along this edge */
  156. }
  157. if(n->parent!=NULL) {
  158. continue; /* We've already visited n */
  159. }
  160. /* n is okay, let's look at its matched neighbour */
  161. AddVtxToTree( g, n, v );
  162. m = n->matchedWith;
  163. assert(!IS_LHS_VTX(m));
  164. if(m->parent!=NULL) {
  165. continue; /* We've already visited m */
  166. }
  167. AddVtxToTree( g, m, n );
  168. if( m->numMatched >= u->numMatched+2 ) {
  169. return m; /* Found an augmenting path */
  170. }
  171. }
  172. }
  173. return NULL;
  174. }
  175. /***** DoFullScan *****/
  176. /* Iterate over all RHS vertices from low-load to high-load.
  177. * At each vertex, do a breadth-first search for a cost-reducing
  178. * path. If one is found, switch along the path to improve the cost.
  179. *
  180. * If any augmentations were made, returns TRUE.
  181. * If no augmentations were made, returns FALSE. */
  182. char __forceinline DoFullScan( Graph *g ) {
  183. Vertex *u, *nextU, *m;
  184. int b;
  185. char fAugmentedSinceStart=FALSE;
  186. #ifdef STATS
  187. int qSizeAtBFSStart;
  188. #endif
  189. /* Iterate over all buckets of vertices */
  190. for( b=0; b<=g->maxRHSLoad-2; b++ ) {
  191. /* Examine the RHS vertices in this bucket */
  192. for( u=g->Buckets[b]; u; u=nextU ) {
  193. assert(u->numMatched==b);
  194. DPRINT( printf("Consider BFS Root %d (Load %d): ",u->id, b); )
  195. nextU=u->fLink;
  196. /* If this vertex has been visited, skip it */
  197. if(u->parent!=NULL) {
  198. DPRINT( printf("Skipping (Marked)\n"); )
  199. continue;
  200. }
  201. #ifdef STATS
  202. qSizeAtBFSStart = g->Qsize;
  203. #endif
  204. /* Do a breadth-first search from u for a cost-reducing path. */
  205. m = DoBFS(g,u);
  206. if( NULL!=m ) {
  207. /* A cost-reducing path from u to m exists. Switch along the path. */
  208. DPRINT( printf("Found augmenting path!\n"); )
  209. UpdateNegPath(g,u,m);
  210. #ifdef STATS
  211. g->stats.TotalAugs++;
  212. g->stats.TotalAugBFSTreeSize+=(g->Qsize-qSizeAtBFSStart);
  213. #endif
  214. fAugmentedSinceStart = TRUE;
  215. }
  216. }
  217. }
  218. /* Update maxRHSLoad */
  219. while(!g->Buckets[g->maxRHSLoad]) g->maxRHSLoad--;
  220. return fAugmentedSinceStart;
  221. }
  222. /***** MainLoop *****/
  223. /* Repeatedly do full-scans of the graph until no more improvements are made. */
  224. void MainLoop( Graph *g ) {
  225. char fMadeImprovement;
  226. int j;
  227. do {
  228. DPRINT( printf("** Restarting from first bucket **\n"); )
  229. #ifdef STATS
  230. g->stats.TotalRestarts++;
  231. #endif
  232. /* Reinitialize the queue */
  233. for(j=0;j<g->Qsize;j++) g->Queue[j]->parent=NULL;
  234. g->Qsize=0;
  235. fMadeImprovement = DoFullScan(g);
  236. } while( fMadeImprovement );
  237. }
  238. /***** LHAlgBFS *****/
  239. /* Main function that implements the LHBFS algorithm for computing
  240. * LH Matchings. */
  241. int LHAlgBFS(Graph *g) {
  242. int err;
  243. DPRINT( printf("--- LHMatch BFS Started ---\n"); )
  244. #ifdef STATS
  245. memset( &g->stats, 0, sizeof(Stats) );
  246. #endif
  247. /* Compute an initial greedy assignment, which may or may not
  248. * have minimum cost. */
  249. err = OrderedGreedyAssignment(g);
  250. if( LH_SUCCESS!=err ) {
  251. return err;
  252. }
  253. #ifdef DUMP
  254. DumpGraph(g);
  255. DumpLoad(g);
  256. #endif
  257. /* Initialize structures needed for BFS: parent pointers and
  258. * queue. */
  259. err = InitializeBFS(g);
  260. if( LH_SUCCESS!=err ) {
  261. return err;
  262. }
  263. /* Insert all RHS vertices into buckets. The purpose of this is
  264. * to sort RHS vertices by matched-degree. */
  265. err = InitializeRHSBuckets(g);
  266. if( LH_SUCCESS!=err ) {
  267. return err;
  268. }
  269. /* Main loop: repeatedly search the graph for ways to improve the
  270. * current assignment */
  271. MainLoop(g);
  272. /* The assignment is now an LH Matching (i.e. optimal cost) */
  273. /* Cleanup */
  274. DestroyQueue(g);
  275. DestroyBuckets(g);
  276. #ifdef DUMP
  277. DumpGraph(g);
  278. DumpLoad(g);
  279. #endif
  280. PrintStats(g);
  281. DPRINT( printf("--- LHMatch BFS Finished ---\n"); )
  282. return LH_SUCCESS;
  283. }