graphPreprocess.c

Go to the documentation of this file.
00001 /* Copyright (c) 2005 by John M. Boyer, All Rights Reserved.  Please see
00002  * License.txt for use and redistribution license. */
00003 /* Copyright (c) 1997-2003 by John M. Boyer, All Rights Reserved.
00004         This code may not be reproduced or disseminated in whole or in part 
00005         without the written permission of the author. */
00006 
00007 #define GRAPHPREPROCESS_C
00008 
00009 #include "graph_boyer.h"
00010 
00011 /********************************************************************
00012  gp_CreateDFSTree
00013  Assigns Depth First Index (DFI) to each vertex.  Also records parent
00014  of each vertex in the DFS tree, and marks DFS tree edges that go from
00015  parent to child.  Forwared arc cycle edges are also distinguished from
00016  edges leading from a DFS tree descendant to an ancestor-- both DFS
00017  edges and back arcs.  This last type is marked with EDGE_BACK, which the
00018  embedder ignores.  Because the embedder works in reverse DFI order,
00019  only forward arcs to children are needed because only the DFS descendants
00020  of a vertex have already been embedded.
00021  ********************************************************************/
00022 int gp_CreateDFSTree (graphP theGraph)
00023 {
00024   stackP theStack = theGraph->theStack;
00025   int DFI = 0,
00026     I,
00027     uparent,
00028     u,
00029     e,
00030     J;
00031   if (theGraph == NULL)
00032     return NOTOK;
00033   if (theGraph->internalFlags & FLAGS_DFSNUMBERED)
00034     return OK;
00035 
00036 /* There are 2M edge records and for each we can push 2 integers,
00037         and M can be up to EDGE_LIMIT * N, so a stack of 4 * EDGE_LIMIT * N
00038         integers suffices. This is already in theGraph structure, so we 
00039         make sure it's empty, then clear all visited flags in prep for the 
00040         Depth first search. */
00041   sp_ClearStack (theStack);
00042   for (I = 0; I < theGraph->N; I++)
00043     theGraph->G[I].visited = 0;
00044 
00045 /* This outer loop causes the connected subgraphs of a disconnected
00046         graph to be numbered */
00047   for (I = 0; I < theGraph->N && DFI < theGraph->N; I++)
00048 
00049   {
00050     if (theGraph->V[I].DFSParent != NIL)
00051       continue;
00052     sp_Push2 (theStack, NIL, NIL);
00053     while (sp_NonEmpty (theStack))
00054 
00055     {
00056       sp_Pop2 (theStack, uparent, e);
00057       u = uparent == NIL ? I : theGraph->G[e].v;
00058       if (!theGraph->G[u].visited)
00059 
00060       {
00061         theGraph->G[u].visited = 1;
00062         theGraph->G[u].v = DFI++;
00063         theGraph->V[u].DFSParent = uparent;
00064         if (e != NIL)
00065 
00066         {
00067           theGraph->G[e].type = EDGE_DFSCHILD;
00068 
00069           // We want the child edges to be at the beginning
00070           // of the adjacency list (link[0] side).
00071 
00072           // Delete the edge from the list
00073           theGraph->G[theGraph->G[e].link[0]].link[1] = theGraph->G[e].link[1];
00074           theGraph->G[theGraph->G[e].link[1]].link[0] = theGraph->G[e].link[0];
00075 
00076           // Tell the edge where it belongs now
00077           theGraph->G[e].link[0] = theGraph->G[uparent].link[0];
00078           theGraph->G[e].link[1] = uparent;
00079 
00080           // Tell the rest of the list where the edge belongs
00081           theGraph->G[uparent].link[0] = e;
00082           theGraph->G[theGraph->G[e].link[0]].link[1] = e;
00083         }
00084 
00085         /* Push all neighbors */
00086         J = theGraph->G[u].link[0];
00087         while (J >= theGraph->N)
00088 
00089         {
00090           sp_Push2 (theStack, u, J);
00091           J = theGraph->G[J].link[0];
00092         }
00093       }
00094 
00095       else
00096 
00097       {
00098 
00099         /* If the edge leads to a visited vertex, then it is either a
00100          * forward cycle edge to a DFS descendant that has already been
00101          * numbered by the depth first search, or it is a 'back' edge
00102          * from a node to a DFS ancestor.  We distinguish between
00103          * back cycle edges and the edge from a node to its DFS parent
00104          * (which is a DFS tree edge not a cycle edge) by testing
00105          * whether the twinArc is marked with EDGE_DFSCHILD. */
00106         if (theGraph->G[uparent].v < theGraph->G[u].v)
00107 
00108         {
00109           theGraph->G[e].type = EDGE_FORWARD;
00110 
00111           // We want all of the forward edges to descendants to
00112           // be at the end of the adjacency list (link[1]).
00113           // The tree edge to the parent and the back edges to
00114           // ancestors are in the middle, between the child edges
00115           // and forward edges. 
00116 
00117           // Delete the edge from the list
00118           theGraph->G[theGraph->G[e].link[0]].link[1] = theGraph->G[e].link[1];
00119           theGraph->G[theGraph->G[e].link[1]].link[0] = theGraph->G[e].link[0];
00120 
00121           // Tell the edge where it belongs now
00122           theGraph->G[e].link[0] = uparent;
00123           theGraph->G[e].link[1] = theGraph->G[uparent].link[1];
00124 
00125           // Tell the rest of the list where the edge belongs
00126           theGraph->G[uparent].link[1] = e;
00127           theGraph->G[theGraph->G[e].link[1]].link[0] = e;
00128         }
00129 
00130         else if (theGraph->G[gp_GetTwinArc (theGraph, e)].type == EDGE_DFSCHILD)
00131           theGraph->G[e].type = EDGE_DFSPARENT;
00132 
00133         else
00134           theGraph->G[e].type = EDGE_BACK;
00135       }
00136     }
00137   }
00138   theGraph->internalFlags |= FLAGS_DFSNUMBERED;
00139   return OK;
00140 }
00141 
00142 
00143 /********************************************************************
00144  gp_SortVertices()
00145  Once depth first numbering has been applied to the graph, the v member
00146  of each vertex contains the DFI.  This routine can reorder the vertices
00147  in linear time so that they appear in ascending order by DFI.  Note
00148  that the field v is then used to store the original number of the
00149  vertex.
00150  Note that this function is not underscored (i.e. not private).  We
00151  export it because it can be called again at a later point to reorder
00152  the vertices back into the original numbering with the DFI values
00153  stored in the v fields (in other words this function is its own inverse).
00154  ********************************************************************/
00155 int gp_SortVertices (graphP theGraph)
00156 {
00157   int I,
00158     N,
00159     M,
00160     e,
00161     J,
00162     srcPos,
00163     dstPos;
00164   vertexRec tempV;
00165   graphNode tempG;
00166   if (theGraph == NULL)
00167     return NOTOK;
00168   if (!(theGraph->internalFlags & FLAGS_DFSNUMBERED))
00169     if (gp_CreateDFSTree (theGraph) != OK)
00170       return NOTOK;
00171 
00172 /* Cache number of vertices and edges into local variables */
00173   N = theGraph->N;
00174   M = theGraph->M;
00175 
00176 /* Change labels of edges from v to DFI(v)-- or vice versa
00177         Also, if any links go back to locations 0 to n-1, then they
00178         need to be changed because we are reordering the vertices */
00179   for (e = 0, J = 2 * N; e < M; e++, J += 2)
00180 
00181   {
00182     theGraph->G[J].v = theGraph->G[theGraph->G[J].v].v;
00183     if (theGraph->G[J].link[0] < N)
00184       theGraph->G[J].link[0] = theGraph->G[theGraph->G[J].link[0]].v;
00185     if (theGraph->G[J].link[1] < N)
00186       theGraph->G[J].link[1] = theGraph->G[theGraph->G[J].link[1]].v;
00187     theGraph->G[J + 1].v = theGraph->G[theGraph->G[J + 1].v].v;
00188     if (theGraph->G[J + 1].link[0] < N)
00189       theGraph->G[J + 1].link[0] = theGraph->G[theGraph->G[J + 1].link[0]].v;
00190     if (theGraph->G[J + 1].link[1] < N)
00191       theGraph->G[J + 1].link[1] = theGraph->G[theGraph->G[J + 1].link[1]].v;
00192   }
00193 
00194 /* Convert DFSParent from v to DFI(v) or vice versa */
00195   for (I = 0; I < N; I++)
00196     if (theGraph->V[I].DFSParent != NIL)
00197       theGraph->V[I].DFSParent = theGraph->G[theGraph->V[I].DFSParent].v;
00198 
00199 /* Sort by 'v using constant time random access. Move each vertex to its
00200         destination 'v', and store its source location in 'v'. */
00201 
00202   /* First we clear the visitation flags.  We need these to help mark
00203    * visited vertices because we change the 'v' field to be the source
00204    * location, so we cannot use index==v as a test for whether the
00205    * correct vertex is in location 'index'. */
00206   for (I = 0; I < N; I++)
00207     theGraph->G[I].visited = 0;
00208 
00209   /* We visit each vertex location, skipping those marked as visited since
00210    * we've already moved the correct vertex into that location. The
00211    * inner loop swaps the vertex at location I into the correct position,
00212    * G[I].v, marks that location as visited, then sets its 'v' field to
00213    * be the location from whence we obtained the vertex record. */
00214   for (I = 0; I < N; I++)
00215 
00216   {
00217     srcPos = I;
00218     while (!theGraph->G[I].visited)
00219 
00220     {
00221       dstPos = theGraph->G[I].v;
00222       tempG = theGraph->G[dstPos];
00223       tempV = theGraph->V[dstPos];
00224       theGraph->G[dstPos] = theGraph->G[I];
00225       theGraph->V[dstPos] = theGraph->V[I];
00226       theGraph->G[I] = tempG;
00227       theGraph->V[I] = tempV;
00228       theGraph->G[dstPos].visited = 1;
00229       theGraph->G[dstPos].v = srcPos;
00230       srcPos = dstPos;
00231     }
00232   }
00233 
00234 /* Invert the bit that records the sort order of the graph */
00235   if (theGraph->internalFlags & FLAGS_SORTEDBYDFI)
00236     theGraph->internalFlags &= ~FLAGS_SORTEDBYDFI;
00237 
00238   else
00239     theGraph->internalFlags |= FLAGS_SORTEDBYDFI;
00240   return OK;
00241 }
00242 
00243 
00244 /********************************************************************
00245  gp_LowpointAndLeastAncestor()
00246         leastAncestor: min(DFI of neighbors connected by backedge)
00247         Lowpoint: min(leastAncestor, Lowpoint of DFSChildren)
00248 
00249  This implementation requires that the vertices be sorted in DFI order
00250  (such that the edge records contain DFI values in their v fields).  An
00251  implementation could be made to run before sorting using the fact that
00252  the value G[G[e].v].v before sorting is equal to G[e].v after the sort.
00253 
00254  For computing Lowpoint, we must do a post-order traversal of the DFS tree.
00255  We push the root of the DFS tree, then we loop while the stack is not empty.
00256  We pop a vertex; if it is not marked, then we are on our way down the DFS
00257  tree, so we mark it and push it back on, followed by pushing its
00258  DFS children.  The next time we pop the node, all of its children
00259  will have been popped, marked+children pushed, and popped again.  On
00260  the second pop of the vertex, we can therefore compute the Lowpoint
00261  values based on the childrens' Lowpoints and the edges in the vertex's
00262  adjacency list.
00263 
00264  A stack of size N suffices because we push each vertex only once.
00265  ********************************************************************/
00266 void gp_LowpointAndLeastAncestor (graphP theGraph)
00267 {
00268   stackP theStack = theGraph->theStack;
00269   int I,
00270     u,
00271     uneighbor,
00272     J,
00273     L,
00274     leastAncestor;
00275   sp_ClearStack (theStack);
00276   for (I = 0; I < theGraph->N; I++)
00277     theGraph->G[I].visited = 0;
00278 
00279 /* This outer loop causes the connected subgraphs of a disconnected
00280         graph to be processed */
00281   for (I = 0; I < theGraph->N; I++)
00282 
00283   {
00284     if (theGraph->G[I].visited)
00285       continue;
00286     sp_Push (theStack, I);
00287     while (sp_NonEmpty (theStack))
00288 
00289     {
00290       sp_Pop (theStack, u);
00291       if (!theGraph->G[u].visited)
00292 
00293       {
00294 
00295         /* Mark u as visited, then push it back on the stack */
00296         theGraph->G[u].visited = 1;
00297         sp_Push (theStack, u);
00298 
00299         /* Push DFS children */
00300         J = theGraph->G[u].link[0];
00301         while (J >= theGraph->N)
00302 
00303         {
00304           if (theGraph->G[J].type == EDGE_DFSCHILD)
00305             sp_Push (theStack, theGraph->G[J].v);
00306 
00307           else
00308             break;
00309           J = theGraph->G[J].link[0];
00310         }
00311       }
00312 
00313       else
00314 
00315       {
00316 
00317         /* Start with high values because we are doing a min function */
00318         L = leastAncestor = u;
00319 
00320         /* Compute L and leastAncestor */
00321         J = theGraph->G[u].link[0];
00322         while (J >= theGraph->N)
00323 
00324         {
00325           uneighbor = theGraph->G[J].v;
00326           if (theGraph->G[J].type == EDGE_DFSCHILD)
00327 
00328           {
00329             if (L > theGraph->V[uneighbor].Lowpoint)
00330               L = theGraph->V[uneighbor].Lowpoint;
00331           }
00332 
00333           else if (theGraph->G[J].type == EDGE_BACK)
00334 
00335           {
00336             if (leastAncestor > uneighbor)
00337               leastAncestor = uneighbor;
00338           }
00339 
00340           else if (theGraph->G[J].type == EDGE_FORWARD)
00341             break;
00342           J = theGraph->G[J].link[0];
00343         }
00344 
00345         /* Assign leastAncestor and Lowpoint to the vertex */
00346         theGraph->V[u].leastAncestor = leastAncestor;
00347         theGraph->V[u].Lowpoint = leastAncestor < L ? leastAncestor : L;
00348       }
00349     }
00350   }
00351 }

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