graphdual.c

Go to the documentation of this file.
00001 #include "graphdual.h"
00002 #ifndef GRD_TEST
00003 #define GRD_TEST 1
00004 #endif
00005 
00006 /* this is an intermediate structure to build our graph */
00007 typedef struct
00008 {
00009   double value;
00010   int tail;
00011   int head;
00012   int index;
00013 }
00014 localEdge_t;
00015 
00016 typedef const localEdge_t *clep_t;
00017 typedef const clep_t *cclep_t;
00018 
00019 static int localEdgeCompare (const void *p1,
00020                              const void *p2)
00021 {
00022   return ((*((cclep_t) (p1)))->value < (*((cclep_t) (p2)))->value) ? 1 : -1;
00023 }
00024 
00025 /* to sort edge indices according to weight (indicated by x). 
00026    assumes that the indices array has already been allocated
00027    and is of size at least nedges */
00028 static int sortEdgeIndices (int nedges,
00029                             int *edges,
00030                             int *indices,
00031                             double *x)
00032 {
00033 
00034   int n;
00035   localEdge_t **edgeArray;
00036 
00037   /* now we need to create the edge array */
00038   edgeArray = (localEdge_t **) malloc (sizeof (localEdge_t *) * nedges);
00039   for (n = 0; n < nedges; n++)
00040   {
00041     edgeArray[n] = (localEdge_t *) malloc (sizeof (localEdge_t));
00042     edgeArray[n]->value = x[n];
00043     edgeArray[n]->head = edges[2 * n];
00044     edgeArray[n]->tail = edges[2 * n + 1];
00045     edgeArray[n]->index = indices[n];
00046   }
00047 
00048   /* now we sort the local edges */
00049   if (nedges > 1)
00050     qsort (edgeArray, (unsigned) nedges, sizeof (localEdge_t *),
00051            localEdgeCompare);
00052   EXIT (edgeArray[0]->value < edgeArray[nedges - 1]->value,
00053         "edgeArray is not well sorted");
00054 
00055   for (n = 0; n < nedges; n++)
00056   {
00057     indices[n] = edgeArray[n]->index;
00058     free (edgeArray[n]);
00059   }
00060 
00061   free (edgeArray);
00062 
00063   return 0;
00064 
00065 }
00066 
00067 /* to sort edges according to weight (indicated by x) */
00068 static int sortEdges (int nedges,
00069                       int *edges,
00070                       double *x)
00071 {
00072 
00073   int n;
00074   localEdge_t **edgeArray;
00075 
00076   /* now we need to create the edge array */
00077   edgeArray = (localEdge_t **) malloc (sizeof (localEdge_t *) * nedges);
00078   for (n = 0; n < nedges; n++)
00079   {
00080     edgeArray[n] = (localEdge_t *) malloc (sizeof (localEdge_t));
00081     edgeArray[n]->value = x[n];
00082     edgeArray[n]->head = edges[2 * n];
00083     edgeArray[n]->tail = edges[2 * n + 1];
00084     edgeArray[n]->index = n;
00085   }
00086 
00087   /* now we sort the local edges */
00088   if (nedges > 1)
00089     qsort (edgeArray, (unsigned) nedges, sizeof (localEdge_t *),
00090            localEdgeCompare);
00091   EXIT (edgeArray[0]->value < edgeArray[nedges - 1]->value,
00092         "edgeArray is not well sorted");
00093 
00094   for (n = 0; n < nedges; n++)
00095   {
00096     edges[2 * n] = edgeArray[n]->head;
00097     edges[2 * n + 1] = edgeArray[n]->tail;
00098     x[n] = edgeArray[n]->value;
00099     free (edgeArray[n]);
00100   }
00101 
00102   free (edgeArray);
00103 
00104   return 0;
00105 
00106 }
00107 
00108 #define GETROOTEDGE(curroot, G) (G->G + G->G[curroot].link[1])
00109 #define GETNEXTEDGE(curedge,curroot, G) ((curedge->link[1] < G->N) ? GETROOTEDGE(curroot,G) : (G->G + curedge->link[1]))
00110 #define ISNODEEMPTY(curroot, G) (G->G[curroot].link[1] < G->N ? 1 : 0 )
00111 #define GETOTHEREND(cedge,nroot,G) (G->G[gp_GetTwinArc(G,(cedge == GETROOTEDGE( nroot, G ) ? (G->G[nroot].link[1]) : (G->G[cedge->link[0]].link[1])))].v)
00112 
00113 /* generate the dual graph and dual planar embedding, and dual planar embeding
00114  * with links to the actual outgoing edges in the bidirected dual. */
00115 EGdGraph_t *getDualBoyer (graphP G,
00116                           int nnodes,
00117                           int nedges,
00118                           double *weigh,
00119                           EGlist_t *** dembed,
00120                           EGmemPool_t * localmem,
00121                           EGlist_t *** lembed)
00122 {
00123 
00124   /* local variables */
00125   size_t os[EG_MENGER_NUMOS] = {
00126     [EG_MENGER_PI] = offsetof (EGmengerNodeData_t, pi),
00127     [EG_MENGER_DIST] = offsetof (EGmengerNodeData_t, dist),
00128     [EG_MENGER_ORIG_DIST] = offsetof (EGmengerNodeData_t, orig_dist),
00129     [EG_MENGER_NDIST] = offsetof (EGmengerNodeData_t, ndist),
00130     [EG_MENGER_ORIG_NDIST] = offsetof (EGmengerNodeData_t, orig_ndist),
00131     [EG_MENGER_MARK] = offsetof (EGmengerNodeData_t, marker),
00132     [EG_MENGER_ORIG_MARK] = offsetof (EGmengerNodeData_t, orig_marker),
00133     [EG_MENGER_FATHER] = offsetof (EGmengerNodeData_t, father),
00134     [EG_MENGER_ORIG_FATHER] = offsetof (EGmengerNodeData_t, orig_father),
00135     [EG_MENGER_HEAP_CONNECTOR] = offsetof (EGmengerNodeData_t, hc),
00136     [EG_MENGER_ECOST] = offsetof (EGmengerEdgeData_t, cost),
00137     [EG_MENGER_REDUCED_ECOST] = offsetof (EGmengerEdgeData_t, reduced_cost),
00138     [EG_MENGER_IS_IN_SOL] = offsetof (EGmengerEdgeData_t, is_in_solution),
00139     [EG_MENGER_EDATA] = offsetof (EGmengerEdgeData_t, data)
00140   };
00141   EGdGraph_t *bdG = 0;
00142   EGdGraphEdge_t *e;
00143   EGdGraphNode_t **node_array;
00144   EGmengerNodeData_t *ndata;
00145   EGmengerEdgeData_t *edata;
00146   int nroot,
00147     nnexti,
00148     i,
00149     rval,
00150     curface,
00151     nnextii;
00152   graphNodeP eproot,
00153     eroot,
00154     epnexti,
00155     epnextii;
00156   unsigned short *e_old,
00157    *e_mark;
00158   const int nFaces = nedges - nnodes + 2;
00159   unsigned char *face_mark;
00160 
00161   /* basic set-up */
00162   ADVTESTL (GD_LEVEL, nnodes != G->N, 0, "number nodes in graph and "
00163             "indicated doesn't match %d != %d", nnodes, G->N);
00164   ADVTESTL (GD_LEVEL, nedges != G->M, 0, "number edges in graph and "
00165             "indicated doesn't match %d != %d", nedges, G->M);
00166   e_old = EGmemPoolSMalloc (localmem, unsigned short,
00167                             G->M);
00168   e_mark = EGmemPoolSMalloc (localmem, unsigned short,
00169                              G->M);
00170   face_mark = EGsMalloc (unsigned char,
00171                          nFaces);
00172   memset (face_mark, 0, sizeof (unsigned char) * nFaces);
00173   node_array = EGmemPoolSMalloc (localmem, EGdGraphNode_t *, nFaces);
00174   *dembed = EGmemPoolSMalloc (localmem, EGlist_t *, nFaces);
00175   if(lembed) *lembed = EGmemPoolSMalloc (localmem, EGlist_t *, nFaces);
00176   bdG = EGnewDGraph (localmem);
00177 
00178   i = gp_Embed (G, EMBEDFLAGS_PLANAR);
00179   rval = gp_SortVertices (G);
00180   EXITRVAL (rval);
00181   if (i != OK)
00182     return 0;
00183 
00184   /* now we have the embedding, we only need to count how 
00185    * many faces there are there and to create bdG, we start
00186    * setting mark and old to 0 for both nodes and edges */
00187   for (nroot = 0; nroot < G->N; nroot++)
00188   {
00189     if (ISNODEEMPTY (nroot, G))
00190       continue;
00191     eproot = GETROOTEDGE (nroot, G);
00192     e_mark[eproot->id] = 0;
00193     e_old[eproot->id] = 0;
00194     /* we set all mark edges in the adjacency list to zero */
00195     for (epnexti = GETNEXTEDGE (eproot, nroot, G); epnexti != eproot;
00196          epnexti = GETNEXTEDGE (epnexti, nroot, G))
00197     {
00198       e_mark[epnexti->id] = 0;
00199       e_old[epnexti->id] = 0;
00200     }
00201   }
00202 
00203   /* ======================================================================= */
00204   /* FIRST STEP: SET THE MARCS IN OLD AND IN MARK */
00205   /* now we look at every edge pair, but discard if we have 
00206    * already traverse the edge in that direction, if we have 
00207    * traversed the edge in the direction end0->end1, then 
00208    * mark = nFace, if we have traversed the edge in the direction 
00209    * end1->end0, then old = nFace */
00210   curface = 1;
00211   /* loop through all nodes */
00212   for (nroot = 0; nroot < G->N; nroot++)
00213   {
00214     /* eproot point to the first edge in the embbedding list */
00215     eproot = GETROOTEDGE (nroot, G);
00216     epnexti = eproot;
00217     do
00218     {
00219       /* loop through neighbours */
00220       if (((unsigned) (epnexti - G->G)) & 1U)
00221       {
00222         /* if we already traversed this edge in this direction we are done */
00223         if (e_mark[epnexti->id])
00224         {
00225           epnexti = GETNEXTEDGE (epnexti, nroot, G);
00226           continue;
00227         }
00228       }
00229       else
00230       {
00231         /* if we already traversed this edge in this direction we are done */
00232         if (e_old[epnexti->id])
00233         {
00234           epnexti = GETNEXTEDGE (epnexti, nroot, G);
00235           continue;
00236         }
00237       }
00238       /* we select nnextii as the next end point of this edge */
00239       nnextii = epnexti->v;
00240 
00241       /* now we loop through the edges of this face */
00242       epnextii = epnexti;
00243       nnexti = nroot;
00244       eroot = epnextii;
00245       do
00246       {                         /* loop through the face */
00247         if (((unsigned) (epnextii - G->G)) & 1U)
00248         {
00249           e_mark[epnextii->id] = curface;
00250           i = e_old[epnextii->id];
00251         }
00252         else
00253         {
00254           e_old[epnextii->id] = curface;
00255           i = e_mark[epnextii->id];
00256         }
00257         /* we update epnextii, eroot, nnexti and nnextii */
00258         epnextii = GETROOTEDGE (nnextii, G);
00259         /* find the epnextii that points to eroot */
00260         while (epnextii->v != nnexti)
00261           epnextii = GETNEXTEDGE (epnextii, nnextii, G);
00262         /* move according to the embedding of edge */
00263         epnextii = GETNEXTEDGE (epnextii, nnextii, G);
00264         eroot = epnextii;
00265         nnexti = nnextii;
00266         nnextii = eroot->v;
00267       } while ((epnextii != epnexti) || (nroot != nnexti));
00268       /* end loop through face */
00269       /* at this stage we have finish a face, and now we create a new one */
00270       curface++;
00271       EXIT (curface - 1 > nFaces, "Number of faces is wrong nFaces %u "
00272             "curface %u", nFaces, curface - 1);
00273       /*update epnexti */
00274       epnexti = GETNEXTEDGE (epnexti, nroot, G);
00275     } while (epnexti != eproot);  /* end loop through neighbours */
00276   }                             /* end loop through all nodes */
00277 
00278   /* ======================================================================= */
00279   /* SECOND PHASE, CREATE DUAL GRAPH AND DUAL EMBEDING */
00280   /* now we look at every edge pair, but discard if we have 
00281    * already traverse the edge in that direction, if we have 
00282    * traversed the edge in the direction end0->end1, then 
00283    * mark = nFace, if we have traversed the edge in the direction 
00284    * end1->end0, then old = nFace */
00285   /* create the nodes and embed lists */
00286   for (i = 0; i < nFaces; i++)
00287   {
00288     ndata = EGnewMengerNodeData (localmem);
00289     node_array[i] = EGdGraphAddNode (bdG, ndata);
00290     (*dembed)[i] = EGnewList (localmem);
00291     if(lembed) (*lembed)[i] = EGnewList (localmem);
00292   }
00293   /* loop through all nodes */
00294   for (nroot = 0; nroot < G->N; nroot++)
00295   {
00296     /* eproot point to the first edge in the embbedding list */
00297     eproot = GETROOTEDGE (nroot, G);
00298     epnexti = eproot;
00299     do
00300     {
00301       /* loop through neighbours */
00302       if (((unsigned) (epnexti - G->G)) & 1U)
00303       {
00304         /* if we already traversed this edge in this direction we are done */
00305         curface = e_mark[epnexti->id];
00306         if (face_mark[curface - 1])
00307         {
00308           epnexti = GETNEXTEDGE (epnexti, nroot, G);
00309           continue;
00310         }
00311       }
00312       else
00313       {
00314         /* if we already traversed this edge in this direction we are done */
00315         curface = e_old[epnexti->id];
00316         if (face_mark[curface - 1])
00317         {
00318           epnexti = GETNEXTEDGE (epnexti, nroot, G);
00319           continue;
00320         }
00321       }
00322       face_mark[curface - 1] = 1;
00323       /* we select nnextii as the next end point of this edge */
00324       nnextii = epnexti->v;
00325 
00326       /* now we loop through the edges of this face */
00327       epnextii = epnexti;
00328       nnexti = nroot;
00329       eroot = epnextii;
00330       do
00331       {                         /* loop through the face */
00332         if (((unsigned) (epnextii - G->G)) & 1U)
00333         {
00334           i = e_old[epnextii->id];
00335         }
00336         else
00337         {
00338           i = e_mark[epnextii->id];
00339         }
00340         /* now we add the corresponding edge to the graph and the embed list */
00341         EGlistPushBack ((*dembed)[curface - 1], (void *) (epnextii->id));
00342         edata = EGnewMengerEdgeData (localmem);
00343         e = EGdGraphAddEdge (bdG, edata,
00344                              node_array[i - 1], node_array[curface - 1]);
00345         EGmengerSetEdgeCost (e, os, EGdijkstraToCost (weigh[epnextii->id]));
00346         EGmengerSetEdgeData (e, os, epnextii);
00347         EGmengerSetEdgeIsInSolution (e, os, 0);
00348         if(lembed) EGlistPushBack((*lembed)[curface - 1], e);
00349         /* we update epnextii, eroot, nnexti and nnextii */
00350         epnextii = GETROOTEDGE (nnextii, G);
00351         /* find the epnextii that points to eroot */
00352         while (epnextii->v != nnexti)
00353           epnextii = GETNEXTEDGE (epnextii, nnextii, G);
00354         /* move according to the embedding of edge */
00355         epnextii = GETNEXTEDGE (epnextii, nnextii, G);
00356         eroot = epnextii;
00357         nnexti = nnextii;
00358         nnextii = eroot->v;
00359       } while ((epnextii != epnexti) || (nroot != nnexti)); /* end loop through face */
00360       /*update epnexti */
00361       epnexti = GETNEXTEDGE (epnexti, nroot, G);
00362     } while (epnexti != eproot);  /* end loop through neighbours */
00363   }                             /* end loop through all nodes */
00364 
00365   /* ending */
00366   EGmemPoolSFree (node_array, EGdGraphNode_t *, nFaces, localmem);
00367   EGmemPoolSFree (e_old, unsigned short,
00368                   G->M,
00369                   localmem);
00370   EGmemPoolSFree (e_mark, unsigned short,
00371                   G->M,
00372                   localmem);
00373   EGfree (face_mark);
00374   return bdG;
00375 }
00376 
00377 /* generate a planar subgraph from a graph by building a maximum weight spanning
00378  * tree and then eliminating edges that make it non planar */
00379 int DPedgeEliminationHeuristic (int nnodes,
00380                                 int nedges,
00381                                 int *edges,
00382                                 double *weight,
00383                                 int *nplanar_edges,
00384                                 int *planar_edges,
00385                                 double *planar_weight,
00386                                 int *nelim_indices,
00387                                 int *elim_indices)
00388 {
00389 
00390 #if DISPLAY_MODE
00391   fprintf (stdout, "EEH: Initiating Edge Elimination Heuristic.\n");
00392   fflush (stdout);
00393 #endif
00394 
00395   int rval;
00396 
00397   rval = sortEdges (nedges, edges, weight);
00398   CHECKRVAL (rval);
00399 
00400 #if DISPLAY_MODE
00401   fprintf (stdout, "EEH: Executing binary search.\n");
00402   fflush (stdout);
00403 #endif
00404 
00405   rval =
00406     DPbinPlanarizeBoyer (nnodes, nedges, 0, edges, weight, nplanar_edges,
00407                          planar_edges, planar_weight, elim_indices);
00408   CHECKRVAL (rval);
00409 
00410   *nelim_indices = nedges - *nplanar_edges;
00411 
00412 #if DISPLAY_MODE
00413   fprintf (stdout, "EEH: Finished.\n");
00414   fflush (stdout);
00415 #endif
00416 
00417   return 0;
00418 
00419 }
00420 
00421 int isPlanarBoyer (int nnodes,
00422                    int nedges,
00423                    int *edges)
00424 {
00425 
00426   int rval,
00427     is_G_planar_b;
00428   graphP G;
00429 
00430   G = gp_New ();
00431   rval = cook2boyerGraph (G, nnodes, nedges, edges);
00432   EXITRVAL (rval);
00433   is_G_planar_b = gp_Embed (G, EMBEDFLAGS_PLANAR);
00434   gp_Free (&G);
00435 
00436   if (is_G_planar_b == OK)
00437     return 1;
00438 
00439   return 0;
00440 
00441 }
00442 
00443 int isPlanarOrMinorBoyer (int nnodes,
00444                           int nedges,
00445                           int *edges,
00446                           int *nmedges,
00447                           int *medges)
00448 {
00449 
00450   int rval,
00451     is_G_planar_b,
00452     nmnodes;
00453   graphP G;
00454 
00455   G = gp_New ();
00456   rval = cook2boyerGraph (G, nnodes, nedges, edges);
00457   EXITRVAL (rval);
00458   is_G_planar_b = gp_Embed (G, EMBEDFLAGS_PLANAR);
00459 
00460   if (is_G_planar_b == OK)
00461   {
00462     gp_Free (&G);
00463     return 1;
00464   }
00465 
00466   gp_SortVertices (G);
00467   extractCookEdgeIds (G, &nmnodes, nmedges, medges);
00468   gp_Free (&G);
00469 
00470   return 0;
00471 
00472 }
00473 
00474 /* This function works with two graphs G1 and G2 spanning a common set of
00475    vertices. It assumes that G2 is a planar graph, and that its edge set 
00476    is strictly contained in that of G1. It finds a graph G3 in between
00477    G1 and G2 that is planar by means of binary search and edge additions.
00478   
00479    nnodes: number of nodes in G1 and G2.
00480    nedges1: number of edges of G1.
00481    nedges2: number of edges of G2.
00482    edges: array of edges in G1. It is assumed that the first nedges2 edges
00483           of the array are the edges of G2. In Cook format.
00484    nedges3: number of edges in G3 (output).
00485    edges3: array with edges in G3 in Cook format (output).
00486    elim_indices: array with the indices of those edges eliminated from edges. */
00487 int DPbinPlanarizeBoyer (int nnodes,
00488                          int nedges1,
00489                          int nedges2,
00490                          int *edges,
00491                          double *weigh,
00492                          int *nedges3,
00493                          int *edges3,
00494                          double *weigh3,
00495                          int *elim_indices)
00496 {
00497 
00498   int nelim = 0,
00499     i,
00500     rval,
00501     current_edge,
00502     is_G_planar_b,
00503     top,
00504     bottom,
00505     middle,
00506     ltop,
00507     lbottom,
00508     lmiddle;
00509   graphP G;
00510 
00511 #if DISPLAY_MODE
00512   fprintf (stdout, "\rBIN: Binary Search Heuristic.\n");
00513   fflush (stdout);
00514 #endif
00515 
00516   /* Make sure that the graph is not-planar before starting                   */
00517   G = gp_New ();
00518   rval = cook2boyerGraph (G, nnodes, nedges1, edges);
00519   EXITRVAL (rval);
00520   is_G_planar_b = gp_Embed (G, EMBEDFLAGS_PLANAR);
00521   gp_Free (&G);
00522 
00523   /* If the graph is planar, return                                           */
00524   if (is_G_planar_b == OK)
00525   {
00526 #if DISPLAY_MODE
00527     fprintf (stdout, "\rBIN: Graph is planar.\n");
00528     fflush (stdout);
00529 #endif
00530     *nedges3 = 0;
00531     return 0;
00532   }
00533 
00534   /* G3 must start as a graph identical to G2                                 */
00535 
00536   *nedges3 = nedges2;
00537 
00538   for (i = 0; i < nedges2; i++)
00539   {
00540     edges3[2 * i] = edges[2 * i];
00541     edges3[2 * i + 1] = edges[2 * i + 1];
00542     weigh3[i] = weigh[i];
00543   }
00544   top = nedges2;
00545   bottom = nedges1;
00546   middle = top + (bottom - top) / 2;
00547 
00548   while ((bottom - top) > 0)
00549   {
00550 
00551     ltop = top;
00552     lbottom = bottom;
00553     lmiddle = ltop + (lbottom - ltop) / 2;
00554 
00555     while (lmiddle != ltop)
00556     {
00557 
00558       /* check if adding edges ltop to lmiddle makes graph planar             */
00559 
00560       current_edge = (*nedges3);
00561       for (i = ltop; i < lmiddle; i++)
00562       {
00563         edges3[2 * (*nedges3)] = edges[2 * i];
00564         edges3[2 * (*nedges3) + 1] = edges[2 * i + 1];
00565         weigh3[*nedges3] = weigh[i];
00566         (*nedges3)++;
00567       }
00568 
00569       /* check if adding it makes the graph non-planar                        */
00570       G = gp_New ();
00571       rval = cook2boyerGraph (G, nnodes, (*nedges3), edges3);
00572       EXITRVAL (rval);
00573       is_G_planar_b = gp_Embed (G, EMBEDFLAGS_PLANAR);
00574       gp_Free (&G);
00575 
00576       /* If the graph is planar, keep the edges and move the ltop down.       */
00577       if (is_G_planar_b == OK)
00578       {
00579         ltop = lmiddle;
00580         lmiddle = ltop + (lbottom - ltop) / 2;
00581         continue;
00582       }
00583 
00584       /* If the graph is not planar, remove the edges and move lbottom up.    */
00585       else
00586       {
00587         (*nedges3) = current_edge;
00588         lbottom = lmiddle;
00589         lmiddle = ltop + (lbottom - ltop) / 2;
00590         continue;
00591       }
00592 
00593     }
00594 
00595     /* We found the edge that needs to be eliminated */
00596     top = lbottom;
00597     elim_indices[nelim++] = lmiddle;
00598 
00599 #if DISPLAY_MODE
00600     fprintf (stdout, "\rBIN: Removing edge (%6d %6d) [%lf]\n",
00601              edges[2 * lmiddle], edges[2 * lmiddle + 1], weigh[lmiddle]);
00602     fflush (stdout);
00603 #endif
00604 
00605     /* If we add the rest of the edges, is the graph planar? */
00606 
00607     current_edge = (*nedges3);
00608     for (i = top; i < bottom; i++)
00609     {
00610       edges3[2 * (*nedges3)] = edges[2 * i];
00611       edges3[2 * (*nedges3) + 1] = edges[2 * i + 1];
00612       weigh3[(*nedges3)] = weigh[i];
00613       (*nedges3)++;
00614     }
00615 
00616     /* check if adding it makes the graph non-planar                        */
00617     G = gp_New ();
00618     rval = cook2boyerGraph (G, nnodes, (*nedges3), edges3);
00619     EXITRVAL (rval);
00620     is_G_planar_b = gp_Embed (G, EMBEDFLAGS_PLANAR);
00621     gp_Free (&G);
00622 
00623     /* If so, break. We are done. */
00624     if (is_G_planar_b == OK)
00625       break;
00626 
00627     /* Else, put the edges back and search for the next bad edge */
00628 
00629     else
00630       (*nedges3) = current_edge;
00631 
00632   }
00633 
00634 #if DISPLAY_MODE
00635   fprintf (stdout, "\rBIN: Eliminated %d edges.\n", nelim);
00636   fprintf (stdout, "BIN: Completed planar sub-graph search.\n");
00637   fflush (stdout);
00638 #endif
00639 
00640   return 0;
00641 
00642 }
00643 
00644 /* for very-safe shrinking... only forks */
00645 
00646 int DPgetTrivialNodesToContract (int nnodes,
00647                                  int nedges,
00648                                  int *edges,
00649                                  double *weight,
00650                                  int *node_1,
00651                                  int *node_2)
00652 {
00653 
00654   int i;
00655   int *degree;
00656 
00657   *node_1 = -1;
00658   *node_2 = -1;
00659 
00660   degree = (int *) calloc ((size_t) nnodes, sizeof (int));
00661 
00662   for (i = 0; i < nedges; i++)
00663     if (weight[i] > 0.99)
00664     {
00665       degree[edges[2 * i]] += 1;
00666       degree[edges[2 * i + 1]] += 1;
00667     }
00668 
00669   for (i = 0; i < nedges; i++)
00670     if (degree[edges[2 * i]] == 2 || degree[edges[2 * i + 1]] == 2)
00671     {
00672       *node_1 = edges[2 * i];
00673       *node_2 = edges[2 * i + 1];
00674       break;
00675     }
00676 
00677   //fprintf(stdout, "edge %d %d\n", *node_1, *node_2);
00678 
00679   free (degree);
00680 
00681   return 0;
00682 
00683 }
00684 
00685 int DPgetNonMinorNodesToContract (int nnodes,
00686                                   int nedges,
00687                                   int *edges,
00688                                   double *weight,
00689                                   int *node_1,
00690                                   int *node_2)
00691 {
00692 
00693   *node_1 = -1;
00694   *node_2 = -1;
00695 
00696   int rval;
00697   int i,
00698     nmedges = 0,
00699    *medges,
00700    *degree,
00701     nmnodes = 0,
00702     max_degree = -1;
00703 
00704   medges = (int *) malloc (sizeof (int) * nedges);
00705   degree = (int *) malloc (sizeof (int) * nnodes);
00706 
00707   memset (degree, 0, sizeof (int) * nnodes);
00708 
00709   /*
00710    * {
00711    * rval = isPlanarOrMinorBoyer(nnodes, nedges, edges, &nmedges, medges);
00712    * 
00713    * if (rval)
00714    * goto CLEANUP;
00715    * }
00716    */
00717 
00718   {
00719     rval = isPlanarBoyer (nnodes, nedges, edges);
00720     if (rval)
00721       goto CLEANUP;
00722 
00723     rval = sortEdges (nedges, edges, weight);
00724     if (rval)
00725       goto CLEANUP;
00726 
00727     rval = DPgetBinMinor (nnodes, nedges, edges, &nmedges, medges, nedges);
00728     if (rval)
00729       goto CLEANUP;
00730   }
00731 
00732   max_degree = 0;
00733 
00734   for (i = 0; i < nmedges; i++)
00735   {
00736     degree[edges[2 * medges[i]]] += 1;
00737     degree[edges[2 * medges[i] + 1]] += 1;
00738 
00739     if (degree[edges[2 * medges[i]]] == 1)
00740       nmnodes++;
00741     if (degree[edges[2 * medges[i]]] > max_degree)
00742       max_degree = degree[edges[2 * medges[i]]];
00743     if (degree[edges[1 + 2 * medges[i]]] == 1)
00744       nmnodes++;
00745     if (degree[edges[1 + 2 * medges[i]]] > max_degree)
00746       max_degree = degree[edges[1 + 2 * medges[i]]];
00747   }
00748 
00749   /*
00750    * {
00751    * 
00752    * int n0 = 0, n2=0, n3=0, n4=0, nX=0;
00753    * 
00754    * for(i=0; i < nnodes; i++)
00755    * {
00756    * if ( degree[i] == 0 ) n0++;  
00757    * else if ( degree[i] == 2 ) n2++;
00758    * else if (degree[i] == 3) n3++;
00759    * else if (degree[i] == 4) n4++;
00760    * else nX++;
00761    * }
00762    * 
00763    * fprintf(stdout, "n0 = %d, n2 = %d, n3 = %d, n4 = %d, nX = %d\n", n0, n2, n3, n4, nX);
00764    * 
00765    * }
00766    */
00767 
00768 
00769 #if 0 == 1
00770   /* first, try to contract 1-paths */
00771   for (i = 0; i < nmedges; i++)
00772     if (degree[edges[2 * medges[i]]] == 2
00773         && degree[edges[2 * medges[i] + 1]] == 2)
00774       if (weight[medges[i]] > 0.999)
00775       {
00776         *node_1 = edges[2 * medges[i]];
00777         *node_2 = edges[2 * medges[i] + 1];
00778         fprintf (stdout, "contracted strong path edge of weight 1\n");
00779         goto DISPLAY;
00780       }
00781 
00782   /* next, try to contract edges of weight = 1 */
00783   for (i = 0; i < nmedges; i++)
00784     if (degree[edges[2 * medges[i]]] == 2
00785         || degree[edges[2 * medges[i] + 1]] == 2)
00786       if (weight[medges[i]] > 0.999)
00787       {
00788         *node_1 = edges[2 * medges[i]];
00789         *node_2 = edges[2 * medges[i] + 1];
00790         fprintf (stdout, "contracted path edge of weight 1\n");
00791         goto DISPLAY;
00792       }
00793 #endif
00794 
00795   /* find one edges that are unrelated to the minor */
00796   for (i = 0; i < nedges; i++)
00797     if (weight[i] > 0.99)
00798       if (!degree[edges[2 * i]] || !degree[edges[2 * i + 1]])
00799       {
00800         *node_1 = edges[2 * i];
00801         *node_2 = edges[2 * i + 1];
00802         fprintf (stdout, "contracted unrelated edge of weight 1\n");
00803         goto DISPLAY;
00804       }
00805 
00806 #if 0 == 1
00807   /* finally, contract minor-paths */
00808   for (i = 0; i < nmedges; i++)
00809     if (degree[edges[2 * medges[i]]] == 2
00810         || degree[edges[2 * medges[i] + 1]] == 2)
00811     {
00812       *node_1 = edges[2 * medges[i]];
00813       *node_2 = edges[2 * medges[i] + 1];
00814       fprintf (stdout, "contracted path edge\n");
00815       goto DISPLAY;
00816     }
00817 #endif
00818 
00819 DISPLAY:
00820 
00821   ADVTESTL (0, max_degree != 3
00822             && max_degree != 4, 1, "Error! unidentified minor");
00823 
00824   if (*node_1 == -1)
00825     saveSubGraph ("contracted_to_minor.x", nnodes, nmedges, edges, medges,
00826                   weight);
00827 
00828 CLEANUP:
00829 
00830 #if DISPLAY_MODE
00831   if (max_degree == 3)
00832     fprintf (stdout,
00833              "MINOR_CONTRACT: Found K3,3 minor (m=%d, n=%d). Nodes to contract: %d and %d.\n",
00834              nmedges, nmnodes, *node_1, *node_2);
00835   else if (max_degree == 4)
00836     fprintf (stdout,
00837              "MINOR_CONTRACT: Found   K5 minor (m=%d, n=%d). Nodes to contract: %d and %d.\n",
00838              nmedges, nmnodes, *node_1, *node_2);
00839   else if (max_degree == -1)
00840     fprintf (stdout,
00841              "MINOR_CONTRACT: Graph is planar. No nodes to contract.\n");
00842   else
00843     fprintf (stdout, "MINOR_CONTRACT: Error! Error!\n");
00844   fflush (stdout);
00845 #endif
00846 
00847   free (medges);
00848   free (degree);
00849 
00850   return 0;
00851 
00852 }
00853 
00854 int DPgetMinorNodesToContract (int nnodes,
00855                                int nedges,
00856                                int *edges,
00857                                int *node_1,
00858                                int *node_2)
00859 {
00860 
00861   *node_1 = -1;
00862   *node_2 = -1;
00863 
00864   int rval,
00865     nfound = 0;
00866   int i,
00867     nmedges = 0,
00868    *medges,
00869    *degree,
00870     nmnodes = 0;
00871 
00872   medges = (int *) malloc (sizeof (int) * nedges);
00873   degree = (int *) malloc (sizeof (int) * nnodes);
00874 
00875   memset (degree, 0, sizeof (int) * nnodes);
00876 
00877   rval = isPlanarOrMinorBoyer (nnodes, nedges, edges, &nmedges, medges);
00878 
00879   if (rval)
00880     goto CLEANUP;
00881 
00882   for (i = 0; i < nmedges; i++)
00883   {
00884     degree[edges[2 * medges[i]]] += 1;
00885     degree[edges[2 * medges[i] + 1]] += 1;
00886     if (degree[edges[2 * medges[i]]] == 1)
00887       nmnodes++;
00888     if (degree[edges[1 + 2 * medges[i]]] == 1)
00889       nmnodes++;
00890   }
00891 
00892   for (i = 0; i < nnodes; i++)
00893   {
00894     if (degree[i] > 2 && !nfound)
00895     {
00896       *node_1 = i;
00897       nfound = 1;
00898     }
00899     else if (degree[i] > 2)
00900     {
00901       *node_2 = i;
00902       break;
00903     }
00904   }
00905 
00906   {
00907 
00908     int error = 0;
00909 
00910     if (degree[*node_1] == 3 && degree[*node_2] != 3)
00911       error = 1;
00912     else if (degree[*node_1] == 4 && degree[*node_2] != 4)
00913       error = 1;
00914     else if (degree[*node_1] != 3 && degree[*node_1] != 4)
00915       error = 1;
00916 
00917     if (error)
00918       for (i = 0; i < nnodes; i++)
00919         if (degree[i] != 0 && degree[i] != 2)
00920           fprintf (stderr, "degree[%d] = %d\n", i, degree[i]);
00921   }
00922 
00923   ADVTESTL (0, *node_1 == -1
00924             || *node_2 == -1, 1, "Failed to find nodes to contract");
00925   ADVTESTL (2, degree[*node_1] == 3
00926             && degree[*node_2] != 3, 1, "Error! unidentified minor");
00927   ADVTESTL (2, degree[*node_1] == 4
00928             && degree[*node_2] != 4, 1, "Error! unidentified minor");
00929   ADVTESTL (2, degree[*node_1] != 3
00930             && degree[*node_1] != 4, 1, "Error! unidentified minor");
00931 
00932 #if DISPLAY_MODE
00933   if (degree[*node_1] == 3)
00934     fprintf (stdout,
00935              "MINOR_CONTRACT: Found K3,3 minor (n=%d, m=%d). Nodes to contract: %d and %d.\n",
00936              nmedges, nmnodes, *node_1, *node_2);
00937   else if (degree[*node_1] == 4)
00938     fprintf (stdout,
00939              "MINOR_CONTRACT: Found   K5 minor (n=%d, m=%d). Nodes to contract: %d and %d.\n",
00940              nmedges, nmnodes, *node_1, *node_2);
00941 #endif
00942 
00943 CLEANUP:
00944 
00945   free (medges);
00946   free (degree);
00947 
00948   return 0;
00949 
00950 }
00951 
00952 int DPfindBadEdgeK (int nnodes,
00953                     int nedges,
00954                     int *edges,
00955                     double *weight,
00956                     int k)
00957 {
00958 
00959   int rval,
00960     bad_edge = -1;
00961   int who,
00962     i,
00963     nmedges = 0,
00964    *medges,
00965    *kedges = 0,
00966    *kindices = 0;
00967   double *kweight = 0,
00968     rvalue;
00969 
00970   if (k == 1)
00971     return (DPfindBadEdge (nnodes, nedges, edges, weight));
00972   else if (k < 1)
00973     return -1;
00974 
00975   medges = (int *) malloc (sizeof (int) * nedges);
00976 
00977   rval = isPlanarOrMinorBoyer (nnodes, nedges, edges, &nmedges, medges);
00978 
00979   //fprintf(stdout, "DPfindBadEdgeK: nmedges = %d\n", nmedges);
00980 
00981   if (rval)
00982     goto CLEANUP;
00983 
00984   if (k > nmedges)
00985     k = nmedges;
00986 
00987   kedges = (int *) malloc (sizeof (int) * 2 * nmedges);
00988   kweight = (double *) malloc (sizeof (double) * nmedges);
00989   kindices = (int *) malloc (sizeof (int) * nmedges);
00990 
00991   for (i = 0; i < nmedges; i++)
00992   {
00993     kedges[2 * i] = edges[2 * (medges[i])];
00994     kedges[2 * i + 1] = edges[2 * (medges[i]) + 1];
00995     kweight[i] = -1 * weight[medges[i]];
00996     kindices[i] = i;
00997   }
00998 
00999   sortEdgeIndices (nmedges, kedges, kindices, kweight);
01000 
01001   rvalue = random ();
01002   rvalue /= EGRAND_MAX;
01003 
01004   who = (int) (k * rvalue);
01005 
01006   if (who == k)
01007     who = k - 1;
01008 
01009   bad_edge = medges[kindices[who]];
01010 
01011 CLEANUP:
01012 
01013   free (medges);
01014 
01015   if (kedges)
01016     free (kedges);
01017   if (kweight)
01018     free (kweight);
01019   if (kindices)
01020     free (kindices);
01021 
01022   return bad_edge;
01023 
01024 }
01025 
01026 int DPfindBadEdge (int nnodes,
01027                    int nedges,
01028                    int *edges,
01029                    double *weight)
01030 {
01031 
01032   int rval;
01033   int i,
01034     nmedges = 0,
01035    *medges,
01036     min_ind = -1;
01037   double min = 200000000.0;
01038 
01039   medges = (int *) malloc (sizeof (int) * nedges);
01040 
01041   rval = isPlanarOrMinorBoyer (nnodes, nedges, edges, &nmedges, medges);
01042 
01043   if (rval)
01044     goto CLEANUP;
01045 
01046   for (i = 0; i < nmedges; i++)
01047     if (weight[medges[i]] < min)
01048     {
01049       min = weight[medges[i]];
01050       min_ind = medges[i];
01051     }
01052 
01053 CLEANUP:
01054 
01055   free (medges);
01056 
01057   return min_ind;
01058 
01059 }
01060 
01061 /* This function works with a graph G1. It finds a graph G2 contained in G1
01062    which is planar by eliminating edges in Kuratowski minors.
01063   
01064    nnodes: number of nodes in G1.
01065    nedges1: number of edges of G1.
01066    edges: array of edges in G1. (Cook format).
01067    nedges3: number of edges in G3 (output).
01068    edges3: array with edges in G3 in Cook format (output).
01069    elim_indices: array with the indices of those edges eliminated from edges. */
01070 int DPfastEdgeEliminationHeuristic (int nnodes,
01071                                     int nedges1,
01072                                     int *edges,
01073                                     double *weight,
01074                                     int *nedges2,
01075                                     int *edges2,
01076                                     double *weight2,
01077                                     int *nelim,
01078                                     int *elim_indices,
01079                                     int k_param)
01080 {
01081 
01082   int i,
01083     iswap,
01084     bad_edge;
01085   //int bad_edge_2;
01086   int *indices = 0;
01087 
01088   double dswap;
01089 
01090 #if DISPLAY_MODE
01091   fprintf (stdout, "\rSEE: Simple Edge Elimination Heuristic.\n");
01092   fflush (stdout);
01093 #endif
01094 
01095   *nelim = 0;
01096 
01097   indices = (int *) malloc (sizeof (int) * nedges1);
01098 
01099   /* Copy G1 unto G2                                                          */
01100 
01101   *nedges2 = nedges1;
01102   for (i = 0; i < nedges1; i++)
01103   {
01104     edges2[2 * i] = edges[2 * i];
01105     edges2[2 * i + 1] = edges[2 * i + 1];
01106     weight2[i] = weight[i];
01107     indices[i] = i;
01108   }
01109 
01110   /* While there is a bad edge in G2, remove it                               */
01111 
01112   bad_edge = DPfindBadEdgeK (nnodes, *nedges2, edges2, weight2, k_param);
01113 
01114   while (bad_edge != -1)
01115   {
01116 
01117     fprintf (stdout, "SEE: Remove edge (%6d %6d) [w = %lf]\n",
01118              edges2[2 * bad_edge], edges2[2 * bad_edge + 1], weight2[bad_edge]);
01119     fflush (stdout);
01120 
01121     /*      
01122      * bad_edge_2 = DPfindBadBinEdgeK(nnodes, *nedges2, edges2, weight2, k_param);
01123      * 
01124      * fprintf(stdout, "SEE: BIN   says: remove edge (%6d %6d) [w = %lf] [i = %d]\n", 
01125      * edges2[2*bad_edge_2], edges2[2*bad_edge_2+1], weight2[bad_edge_2], bad_edge_2);
01126      * fflush(stdout);
01127      */
01128 
01129     elim_indices[*nelim] = indices[bad_edge];
01130     (*nelim) += 1;
01131 
01132     iswap = indices[bad_edge];
01133     indices[bad_edge] = indices[*nedges2 - 1];
01134     indices[*nedges2 - 1] = iswap;
01135 
01136     iswap = edges2[2 * bad_edge];
01137     edges2[2 * bad_edge] = edges2[2 * (*nedges2 - 1)];
01138     edges2[2 * (*nedges2 - 1)] = iswap;
01139 
01140     iswap = edges2[2 * bad_edge + 1];
01141     edges2[2 * bad_edge + 1] = edges2[2 * (*nedges2 - 1) + 1];
01142     edges2[2 * (*nedges2 - 1) + 1] = iswap;
01143 
01144     dswap = weight2[bad_edge];
01145     weight2[bad_edge] = weight2[*nedges2 - 1];
01146     weight2[*nedges2 - 1] = dswap;
01147 
01148     (*nedges2) -= 1;
01149 
01150     bad_edge = DPfindBadEdgeK (nnodes, *nedges2, edges2, weight2, k_param);
01151 
01152   }
01153 
01154   free (indices);
01155 
01156 #if DISPLAY_MODE
01157   fprintf (stdout, "\rBIN: Eliminated %d edges.\n", *nelim);
01158   fprintf (stdout, "BIN: Completed planar sub-graph search.\n");
01159   fflush (stdout);
01160 #endif
01161 
01162   return 0;
01163 
01164 }
01165 
01166 int DPfindBadBinEdge (int nnodes,
01167                       int nedges,
01168                       int *edges)
01169 {
01170 
01171   /* local variables */
01172   EGmemPool_t *mem;
01173   int ltop,
01174     lbottom,
01175     lmiddle;
01176   int is_G_planar_b,
01177     res = INT_MAX;
01178 
01179   /* basic set-up */
01180   mem = EGnewMemPool (8192, EGmemPoolNewSize, 4096);
01181   is_G_planar_b = isPlanarBoyer (nnodes, nedges, edges);
01182   if (is_G_planar_b)
01183     goto CLEANUP;
01184 
01185   /* prepare to the binary search */
01186   ltop = nedges - 1;
01187   lbottom = 0;
01188   lmiddle = lbottom + (ltop - lbottom) / 2;
01189 
01190   while (ltop != lbottom)
01191   {
01192 
01193     /* check if adding it makes the graph non-planar */
01194     is_G_planar_b = isPlanarBoyer (nnodes, lmiddle + 1, edges);
01195 
01196     /* if so, leave them and move lbottom up. */
01197     if (is_G_planar_b)
01198       lbottom = lmiddle + 1;
01199 
01200     /* if not, remove them and move ltop down */
01201     else
01202       ltop = lmiddle;
01203 
01204     lmiddle = lbottom + (ltop - lbottom) / 2;
01205 
01206   }                             /* end while */
01207 
01208   is_G_planar_b = isPlanarBoyer (nnodes, lmiddle + 1, edges);
01209 
01210   /* We found the edge that needs to be eliminated */
01211   if (lbottom < nedges)
01212     res = lbottom;
01213 
01214   /* ending */
01215 CLEANUP:
01216   EGfreeMemPool (mem);
01217   return res;
01218 }
01219 
01220 int DPfindBadBinEdgeK (int nnodes,
01221                        int nedges,
01222                        int *edges,
01223                        double *weight,
01224                        int k)
01225 {
01226 
01227   int rval,
01228     bad_edge = -1;
01229   int who,
01230     nmedges = 0,
01231    *medges;
01232   double rvalue;
01233 
01234   if (k == 1)
01235     return (DPfindBadEdge (nnodes, nedges, edges, weight));
01236   else if (k < 1)
01237     return -1;
01238 
01239   medges = (int *) malloc (sizeof (int) * nedges);
01240 
01241   rval = isPlanarBoyer (nnodes, nedges, edges);
01242 
01243   if (rval)
01244     goto CLEANUP;
01245 
01246   if (k > nedges)
01247     k = nedges;
01248 
01249   //rval = DPgetBinMinor(nnodes, nedges, edges, &nmedges, medges, nedges);
01250   rval = DPgetBinMinor (nnodes, nedges, edges, &nmedges, medges, k);
01251   CHECKRVAL (rval);
01252 
01253   //fprintf(stdout, "DPfindBadBinEdgeK: nmedges = %d\n", nmedges);
01254 
01255   rvalue = random ();
01256   rvalue /= EGRAND_MAX;
01257 
01258   who = (int) (k * rvalue);
01259 
01260   if (who == k)
01261     who = k - 1;
01262 
01263   bad_edge = medges[who];
01264 
01265 CLEANUP:
01266 
01267   free (medges);
01268 
01269   return bad_edge;
01270 
01271 }
01272 
01273 int DPgetBinMinor (int nnodes,
01274                    int nedges,
01275                    int *edges,
01276                    int *nmedges,
01277                    int *medges,
01278                    int k)
01279 {
01280 
01281   /* local variables */
01282 
01283   EGmemPool_t *mem;
01284   mem = EGnewMemPool (512, EGmemPoolNewSize, 4096);
01285 
01286   int badedge = 0,
01287    *ledges,
01288    *lind,
01289     lnedges = nedges,
01290     itmp;
01291   register int i;
01292 
01293   /* basic set-up */
01294   *nmedges = 0;
01295   ledges = (int *) malloc (sizeof (int) * nedges * 2);
01296   lind = (int *) malloc (sizeof (int) * nedges);
01297   memcpy (ledges, edges, sizeof (int) * nedges * 2);
01298   for (i = nedges; i--;)
01299     lind[i] = i;
01300 
01301   while ((*nmedges < lnedges) && (*nmedges < k))
01302   {
01303 
01304     /* get next */
01305     badedge = DPfindBadBinEdge (nnodes, lnedges, ledges);
01306     if (badedge >= lnedges || badedge < *nmedges)
01307       break;
01308 
01309     /* swap end 0 */
01310     itmp = ledges[badedge * 2];
01311     ledges[badedge * 2] = ledges[(*nmedges) * 2];
01312     ledges[(*nmedges) * 2] = itmp;
01313 
01314     /* swap end 1 */
01315     itmp = ledges[badedge * 2 + 1];
01316     ledges[badedge * 2 + 1] = ledges[(*nmedges) * 2 + 1];
01317     ledges[(*nmedges) * 2 + 1] = itmp;
01318 
01319     /* save index */
01320     medges[(*nmedges)] = lind[badedge];
01321 
01322     /* swap index */
01323     itmp = lind[*nmedges];
01324     lind[*nmedges] = lind[badedge];
01325     lind[badedge] = itmp;
01326 
01327     /* increment */
01328     (*nmedges) += 1;
01329     lnedges = badedge + 1;
01330 
01331   }                             /* end while */
01332 
01333   /* ending */
01334   EGfreeMemPool (mem);
01335   free (ledges);
01336   free (lind);
01337   return 0;
01338 }

Generated on Thu Oct 20 14:58:41 2005 for DominoParitySeparator by  doxygen 1.4.5