graphEmbed.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 GRAPH_C
00008 
00009 #include <stdlib.h>
00010 
00011 #include "graph_boyer.h"
00012 
00013 /* Imported functions */
00014 extern void _InitGraphNode (graphP theGraph,
00015                             int I);
00016 extern void _FillVisitedFlags (graphP,
00017                                int);
00018 extern int _IsolateKuratowskiSubgraph (graphP theGraph,
00019                                        int I);
00020 
00021 /* Private functions (some are exported to system only) */
00022 void _CreateSortedSeparatedDFSChildLists (graphP theGraph);
00023 void _CreateFwdArcLists (graphP theGraph);
00024 void _CreateDFSTreeEmbedding (graphP theGraph);
00025 void _EmbedBackEdgeToDescendant (graphP theGraph,
00026                                  int RootSide,
00027                                  int RootVertex,
00028                                  int W,
00029                                  int WPrevLink);
00030 int _GetNextVertexOnExternalFace (graphP theGraph,
00031                                   int curVertex,
00032                                   int *pPrevLink);
00033 void _InvertVertex (graphP theGraph,
00034                     int V);
00035 void _MergeVertex (graphP theGraph,
00036                    int W,
00037                    int WPrevLink,
00038                    int R);
00039 void _MergeBicomps (graphP theGraph);
00040 void _RecordPertinentChildBicomp (graphP theGraph,
00041                                   int I,
00042                                   int RootVertex);
00043 void _WalkUp (graphP theGraph,
00044               int I,
00045               int J);
00046 void _WalkDown (graphP theGraph,
00047                 int I,
00048                 int RootVertex);
00049 void _OrientVerticesInEmbedding (graphP theGraph);
00050 void _OrientVerticesInBicomp (graphP theGraph,
00051                               int BicompRoot,
00052                               int PreserveSigns);
00053 int _JoinBicomps (graphP theGraph);
00054 
00055 /********************************************************************
00056  _CreateSortedSeparatedDFSChildLists()
00057  We create a separatedDFSChildList in each vertex which contains the
00058  Lowpoint values of the vertex's DFS children sorted in non-descending order.
00059  To accomplish this in linear time for the whole graph, we must not
00060  sort the DFS children in each vertex, but rather bucket sort the
00061  Lowpoint values of all vertices, then traverse the buckets sequentially,
00062  adding each vertex to its parent's separatedDFSChildList.
00063  Note that this is a specialized bucket sort that achieves O(n)
00064  worst case rather than O(n) expected time due to the simplicity
00065  of the sorting problem.  Specifically, we know that the Lowpoint values
00066  are between 0 and N-1, so we create buckets for each value.
00067  Collisions occur only when two keys are equal, so there is no
00068  need to sort the buckets (hence O(n) worst case).
00069  ********************************************************************/
00070 void _CreateSortedSeparatedDFSChildLists (graphP theGraph)
00071 {
00072   int *buckets;
00073   listCollectionP bin;
00074   int I,
00075     J,
00076     N,
00077     DFSParent,
00078     theList;
00079   N = theGraph->N;
00080   buckets = theGraph->buckets;
00081   bin = theGraph->bin;
00082 
00083   /* Initialize the bin and all the buckets to be empty */
00084   LCReset (bin);
00085   for (I = 0; I < N; I++)
00086     buckets[I] = NIL;
00087 
00088   /* For each vertex, add it to the bucket whose index is equal to
00089    * the Lowpoint of the vertex. */
00090   for (I = 0; I < N; I++)
00091 
00092   {
00093     J = theGraph->V[I].Lowpoint;
00094     buckets[J] = LCAppend (bin, buckets[J], I);
00095   }
00096 
00097   /* For each bucket, add each vertex in the bucket to the
00098    * separatedDFSChildList of its DFSParent.  Since lower numbered buckets
00099    * are processed before higher numbered buckets, vertices with lower
00100    * Lowpoint values are added before those with higher Lowpoint values,
00101    * so the separatedDFSChildList of each vertex is sorted by Lowpoint */
00102   for (I = 0; I < N; I++)
00103 
00104   {
00105     if ((J = buckets[I]) != NIL)
00106 
00107     {
00108       while (J != NIL)
00109 
00110       {
00111         DFSParent = theGraph->V[J].DFSParent;
00112         if (DFSParent != NIL && DFSParent != J)
00113 
00114         {
00115           theList = theGraph->V[DFSParent].separatedDFSChildList;
00116           theList = LCAppend (theGraph->DFSChildLists, theList, J);
00117           theGraph->V[DFSParent].separatedDFSChildList = theList;
00118         }
00119         J = LCGetNext (bin, buckets[I], J);
00120       }
00121     }
00122   }
00123 }
00124 
00125 
00126 /********************************************************************
00127  _CreateFwdArcLists()
00128 
00129  Puts the forward arcs (back edges from a vertex to its descendants)
00130  into a circular list indicated by the fwdArcList member, a task 
00131  simplified by the fact that they have already been placed in link[1] 
00132  succession.
00133  ********************************************************************/
00134 void _CreateFwdArcLists (graphP theGraph)
00135 {
00136   int I,
00137     Jfirst,
00138     Jnext,
00139     Jlast;
00140   for (I = 0; I < theGraph->N; I++)
00141 
00142   {
00143     Jfirst = theGraph->G[I].link[1];
00144 
00145     /* If the vertex has any forward edges, then ... */
00146 
00147     /* WARNING: This was taken out, and then put back in... WHY??? */
00148     if (Jfirst < theGraph->N)
00149       continue;
00150 
00151     /* END OF WARNING */
00152     if (theGraph->G[Jfirst].type == EDGE_FORWARD)
00153 
00154     {
00155 
00156       /* Find the end of the forward edge list */
00157       Jnext = Jfirst;
00158       while (theGraph->G[Jnext].type == EDGE_FORWARD)
00159         Jnext = theGraph->G[Jnext].link[1];
00160       Jlast = theGraph->G[Jnext].link[0];
00161 
00162       /* Remove the forward edges from the adjacency list of I */
00163       theGraph->G[Jnext].link[0] = I;
00164       theGraph->G[I].link[1] = Jnext;
00165 
00166       /* Make a circular forward edge list */
00167       theGraph->V[I].fwdArcList = Jfirst;
00168       theGraph->G[Jfirst].link[0] = Jlast;
00169       theGraph->G[Jlast].link[1] = Jfirst;
00170     }
00171   }
00172 }
00173 
00174 
00175 /********************************************************************
00176  _CreateDFSTreeEmbedding()
00177 
00178  Each vertex receives only its parent arc in the adjacency list, and
00179  the corresponding child arc is placed in the adjacency list of a root 
00180  copy of the parent.  Each root copy of a vertex is uniquely associated 
00181  with a child C, so it is simply stored at location C+N.
00182 
00183  The forward arcs are not lost because they are already in the 
00184  fwdArcList of each vertex.  Each back arc can be reached as the
00185  twin arc of a forward arc, and the two are embedded together when
00186  the forward arc is processed.  Finally, the child arcs are initially
00187  placed in root copies of vertices, not the vertices themselves, but
00188  the child arcs are merged into the vertices as the embedder progresses.
00189  ********************************************************************/
00190 void _CreateDFSTreeEmbedding (graphP theGraph)
00191 {
00192   int N,
00193     I,
00194     J,
00195     Jtwin,
00196     R;
00197   N = theGraph->N;
00198   for (I = 0, R = N; I < N; I++, R++)
00199 
00200   {
00201     if (theGraph->V[I].DFSParent == NIL)
00202 
00203     {
00204       theGraph->G[I].link[0] = theGraph->G[I].link[1] = I;
00205     }
00206 
00207     else
00208 
00209     {
00210       J = theGraph->G[I].link[0];
00211       while (theGraph->G[J].type != EDGE_DFSPARENT)
00212         J = theGraph->G[J].link[0];
00213       theGraph->G[I].link[0] = theGraph->G[I].link[1] = J;
00214       theGraph->G[J].link[0] = theGraph->G[J].link[1] = I;
00215       theGraph->G[J].v = R;
00216       Jtwin = gp_GetTwinArc (theGraph, J);
00217       theGraph->G[R].link[0] = theGraph->G[R].link[1] = Jtwin;
00218       theGraph->G[Jtwin].link[0] = theGraph->G[Jtwin].link[1] = R;
00219       theGraph->extFace[R].link[0] = theGraph->extFace[R].link[1] = I;
00220       theGraph->extFace[I].link[0] = theGraph->extFace[I].link[1] = R;
00221     }
00222   }
00223 }
00224 
00225 
00226 /********************************************************************
00227  _EmbedBackEdgeToDescendant()
00228  The Walkdown has found a descendant vertex W to which it can 
00229  attach a back edge up to the root of the bicomp it is processing.
00230  The RootSide and WPrevLink indicate the parts of the external face
00231  that will be replaced at each endpoint of the back edge.
00232  ********************************************************************/
00233 void _EmbedBackEdgeToDescendant (graphP theGraph,
00234                                  int RootSide,
00235                                  int RootVertex,
00236                                  int W,
00237                                  int WPrevLink)
00238 {
00239   int fwdArc,
00240     backArc,
00241     parentCopy;
00242 
00243   /* We get the two edge records of the back edge to embed.
00244    * The Walkup recorded in W's adjacentTo the index of the forward arc 
00245    * from the root's parent copy to the descendant W. */
00246   fwdArc = theGraph->V[W].adjacentTo;
00247   backArc = gp_GetTwinArc (theGraph, fwdArc);
00248 
00249   /* The forward arc is removed from the fwdArcList of the root's parent copy. */
00250   parentCopy = theGraph->V[RootVertex - theGraph->N].DFSParent;
00251   if (theGraph->V[parentCopy].fwdArcList == fwdArc)
00252 
00253   {
00254     if (theGraph->G[fwdArc].link[0] == fwdArc)
00255       theGraph->V[parentCopy].fwdArcList = NIL;
00256 
00257     else
00258       theGraph->V[parentCopy].fwdArcList = theGraph->G[fwdArc].link[0];
00259   }
00260   theGraph->G[theGraph->G[fwdArc].link[0]].link[1] =
00261     theGraph->G[fwdArc].link[1];
00262   theGraph->G[theGraph->G[fwdArc].link[1]].link[0] =
00263     theGraph->G[fwdArc].link[0];
00264 
00265   /* The forward arc is added to the adjacency list of the RootVertex. */
00266   theGraph->G[fwdArc].link[1 ^ RootSide] = RootVertex;
00267   theGraph->G[fwdArc].link[RootSide] = theGraph->G[RootVertex].link[RootSide];
00268   theGraph->G[theGraph->G[RootVertex].link[RootSide]].link[1 ^ RootSide] =
00269     fwdArc;
00270   theGraph->G[RootVertex].link[RootSide] = fwdArc;
00271 
00272   /* The back arc is added to the adjacency list of W. */
00273   theGraph->G[backArc].v = RootVertex;
00274   theGraph->G[backArc].link[1 ^ WPrevLink] = W;
00275   theGraph->G[backArc].link[WPrevLink] = theGraph->G[W].link[WPrevLink];
00276   theGraph->G[theGraph->G[W].link[WPrevLink]].link[1 ^ WPrevLink] = backArc;
00277   theGraph->G[W].link[WPrevLink] = backArc;
00278 
00279   /* Link the two endpoint vertices together on the external face */
00280   theGraph->extFace[RootVertex].link[RootSide] = W;
00281   theGraph->extFace[W].link[WPrevLink] = RootVertex;
00282 }
00283 
00284 
00285 /********************************************************************
00286  _GetNextVertexOnExternalFace()
00287  Each vertex contains a link[0] and link[1] that link it into its
00288  list of edges.  If the vertex is on the external face, then the two
00289  edge nodes pointed to by link[0] and link[1] are also on the
00290  external face.  We want to take one of those edges to get to the
00291  next vertex on the external face.
00292  On input *pPrevLink indicates which link we followed to arrive at
00293  curVertex.  On output *pPrevLink will be set to the link we follow to
00294  get into the next vertex.
00295  To get to the next vertex, we use the opposite link from the one used
00296  to get into curVertex.  This takes us to an edge node.  The twinArc
00297  of that edge node, carries us to an edge node in the next vertex.
00298  At least one of the two links in that edge node will lead to a vertex
00299  node in G, which is the next vertex.  Once we arrive at the next
00300  vertex, at least one of its links will lead back to the edge node, and
00301  that link becomes the output value of *pPrevLink.
00302  ********************************************************************/
00303 int _GetNextVertexOnExternalFace (graphP theGraph,
00304                                   int curVertex,
00305                                   int *pPrevLink)
00306 {
00307   int arc,
00308     nextArc,
00309     nextVertex,
00310     newPrevLink;
00311 
00312   /* Exit curVertex from whichever link was not previously used to enter it */
00313   arc = theGraph->G[curVertex].link[1 ^ (*pPrevLink)];
00314   nextArc = gp_GetTwinArc (theGraph, arc);
00315   nextVertex = theGraph->G[nextArc].link[newPrevLink = 0];
00316   if (nextVertex >= 2 * theGraph->N)
00317     nextVertex = theGraph->G[nextArc].link[newPrevLink = 1];
00318 
00319   /* The setting above is how we exited an edge record to get to the
00320    * next vertex.  The reverse pointer leads back from the vertex to
00321    * the edge record. */
00322   newPrevLink = 1 ^ newPrevLink;
00323 
00324   /* This if stmt assigns the new prev link that tells us which edge
00325    * record was used to enter nextVertex (so that we exit from the
00326    * opposing edge record).
00327    * However, if we are in a singleton bicomp, then both links in nextVertex
00328    * lead back to curVertex, so newPrevLink may get stop at the zero setting
00329    * when it should become one.
00330    * We want the two arcs of a singleton bicomp to act like a cycle, so the
00331    * edge record given as the prev link for curVertex should be the same as
00332    * the prev link for nextVertex.
00333    * So, we only need to modify the prev link if the links in nextVertex
00334    * are not equal. */
00335   if (theGraph->G[nextVertex].link[0] != theGraph->G[nextVertex].link[1])
00336     *pPrevLink = newPrevLink;
00337   return nextVertex;
00338 }
00339 
00340 
00341 /********************************************************************
00342  _InvertVertex()
00343  This function flips the orientation of a single vertex such that
00344  instead of using link[0] successors to go clockwise (or counterclockwise)
00345  around a vertex's adjacency list, link[1] successors would be used.
00346  The loop is constructed using do-while so we can swap the links
00347  in the vertex node as well as each arc node.
00348  ********************************************************************/
00349 void _InvertVertex (graphP theGraph,
00350                     int V)
00351 {
00352   int J,
00353     JTemp;
00354   J = V;
00355 
00356   do
00357   {
00358     JTemp = theGraph->G[J].link[0];
00359     theGraph->G[J].link[0] = theGraph->G[J].link[1];
00360     theGraph->G[J].link[1] = JTemp;
00361     J = theGraph->G[J].link[0];
00362   } while (J >= 2 * theGraph->N);
00363   JTemp = theGraph->extFace[V].link[0];
00364   theGraph->extFace[V].link[0] = theGraph->extFace[V].link[1];
00365   theGraph->extFace[V].link[1] = JTemp;
00366 }
00367 
00368 
00369 /********************************************************************
00370  _SetSignOfChildEdge()
00371  Finds the DFSCHILD edge of the vertex, and sets its sign.
00372  ********************************************************************/
00373 void _SetSignOfChildEdge (graphP theGraph,
00374                           int V,
00375                           int sign)
00376 {
00377   int J;
00378   J = theGraph->G[V].link[0];
00379   while (J >= 2 * theGraph->N)
00380 
00381   {
00382     if (theGraph->G[J].type == EDGE_DFSCHILD)
00383 
00384     {
00385       theGraph->G[J].sign = sign;
00386       break;
00387     }
00388     J = theGraph->G[J].link[0];
00389   }
00390 }
00391 
00392 
00393 /********************************************************************
00394  _MergeVertex()
00395  The merge step joins the vertex W to the root R of a child bicompRoot,
00396  which is a root copy of W appearing in the region N to 2N-1.
00397 
00398  Actually, the first step of this is to redirect all of the edges leading
00399  into R so that they indicate W as the neighbor instead of R.
00400  For each edge node pointing to R, we set the 'v' field to W.  Once an
00401  edge is redirected from a root copy R to a parent copy W, the edge is
00402  never redirected again, so we associate the cost of the redirection
00403  as constant per edge, which maintains linear time performance.
00404 
00405  After this is done, a regular circular list union occurs. The only
00406  consideration is that WPrevLink is used to indicate the two edge
00407  records e_w and e_r that will become consecutive in the resulting
00408  adjacency list of W.  We set e_w to W's link[WPrevLink] and e_r to
00409  R's link[1^WPrevLink] so that e_w and e_r indicate W and R with
00410  opposing links, which become free to be cross-linked.  Finally,
00411  the edge record e_ext, set equal to R's link[WPrevLink], is the edge
00412  that, with e_r, held R to the external face.  Now, e_ext will be the
00413  new link[WPrevLink] edge record for W.  If e_w and e_r become part
00414  of a proper face, then e_ext and W's link[1^WPrevLink] are the two
00415  edges that hold W to the external face.
00416  ********************************************************************/
00417 void _MergeVertex (graphP theGraph,
00418                    int W,
00419                    int WPrevLink,
00420                    int R)
00421 {
00422   int J,
00423     JTwin,
00424     N;
00425   int e_w,
00426     e_r,
00427     e_ext;
00428   N = theGraph->N;
00429 
00430   /* All arcs leading into R from its neighbors must be changed
00431    * to say that they are leading into W */
00432   J = theGraph->G[R].link[0];
00433   while (J >= 2 * N)
00434 
00435   {
00436     JTwin = gp_GetTwinArc (theGraph, J);
00437     theGraph->G[JTwin].v = W;
00438     J = theGraph->G[J].link[0];
00439   }
00440 
00441   /* Obtain the edge records involved in the circular list union */
00442   e_w = theGraph->G[W].link[WPrevLink];
00443   e_r = theGraph->G[R].link[1 ^ WPrevLink];
00444   e_ext = theGraph->G[R].link[WPrevLink];
00445 
00446   /* WPrevLink leads away from W to e_w, so 1^WPrevLink in e_w leads back to W.
00447    * Now it must lead to e_r.  Likewise, e_r needs to lead back to e_w
00448    * with the opposing link, which is link[WPrevLink] */
00449   theGraph->G[e_w].link[1 ^ WPrevLink] = e_r;
00450   theGraph->G[e_r].link[WPrevLink] = e_w;
00451 
00452   /* Now we cross-link W's link[WPrevLink] and link[1^WPrevLink] in the
00453    * edge record e_ext */
00454   theGraph->G[W].link[WPrevLink] = e_ext;
00455   theGraph->G[e_ext].link[1 ^ WPrevLink] = W;
00456 
00457   /* Erase the entries in R, which a root copy that is no longer needed. */
00458   _InitGraphNode (theGraph, R);
00459 }
00460 
00461 
00462 /********************************************************************
00463  _MergeBicomps()
00464  Merges all biconnected components at the cut vertices indicated by
00465  entries on the stack.
00466  ********************************************************************/
00467 void _MergeBicomps (graphP theGraph)
00468 {
00469   int R,
00470     Rout,
00471     Z,
00472     ZPrevLink;
00473   int theList,
00474     DFSChild,
00475     RootId;
00476   int extFaceVertex;
00477   while (sp_NonEmpty (theGraph->theStack))
00478 
00479   {
00480     sp_Pop2 (theGraph->theStack, R, Rout);
00481     sp_Pop2 (theGraph->theStack, Z, ZPrevLink);
00482 
00483     /* The external faces of the bicomps containing R and Z will
00484      * form two corners at Z.  One corner will become part of the
00485      * internal face formed by adding the new back edge. The other 
00486      * corner will be the new external face corner at Z.  
00487      * We first want to update the links at Z to reflect this. */
00488     extFaceVertex = theGraph->extFace[R].link[1 ^ Rout];
00489     theGraph->extFace[Z].link[ZPrevLink] = extFaceVertex;
00490     if (theGraph->extFace[extFaceVertex].link[0] ==
00491         theGraph->extFace[extFaceVertex].link[1])
00492       theGraph->extFace[extFaceVertex].link[Rout ^ theGraph->
00493                                             extFace[extFaceVertex].
00494                                             inversionFlag] = Z;
00495 
00496     else
00497       theGraph->extFace[extFaceVertex].link[theGraph->extFace[extFaceVertex].
00498                                             link[0] == R ? 0 : 1] = Z;
00499 
00500     /* If the path used to enter Z is opposed to the path
00501      * used to exit R, then we have to flip the bicomp
00502      * rooted at R, which we signify by inverting R
00503      * then setting the sign on its DFS child edge to
00504      * indicate that its descendants must be flipped later */
00505     if (ZPrevLink == Rout)
00506 
00507     {
00508       if (theGraph->G[R].link[0] != theGraph->G[R].link[1])
00509         _InvertVertex (theGraph, R);
00510       _SetSignOfChildEdge (theGraph, R, -1);
00511       Rout = 1 ^ ZPrevLink;
00512     }
00513 
00514     /* R is no longer pertinent to Z since we are about to
00515      * merge R into Z, so we delete R from its pertinent
00516      * bicomp list (Walkdown gets R from the head of the list). */
00517     RootId = R - theGraph->N;
00518     theList = theGraph->V[Z].pertinentBicompList;
00519     theList = LCDelete (theGraph->BicompLists, theList, RootId);
00520     theGraph->V[Z].pertinentBicompList = theList;
00521 
00522     /* As a result of the merge, the DFS child of Z must be removed 
00523      * from Z's SeparatedDFSChildList because the child has just 
00524      * been joined directly to Z, rather than being separated by a 
00525      * root copy. */
00526     DFSChild = R - theGraph->N;
00527     theList = theGraph->V[Z].separatedDFSChildList;
00528     theList = LCDelete (theGraph->DFSChildLists, theList, DFSChild);
00529     theGraph->V[Z].separatedDFSChildList = theList;
00530 
00531     /* Now we push R into Z, eliminating R */
00532     _MergeVertex (theGraph, Z, ZPrevLink, R);
00533   }
00534 }
00535 
00536 
00537 /********************************************************************
00538  _GetPertinentChildBicomp()
00539  Returns the root of a pertinent child bicomp for the given vertex.
00540  Note: internally active roots are stored first (see _RecordPertinentChildBicomp())
00541  ********************************************************************/
00542 
00543 #define _GetPertinentChildBicomp(theGraph, W) \
00544   (theGraph->V[W].pertinentBicompList == NIL ? NIL \
00545    : theGraph->V[W].pertinentBicompList + theGraph->N)
00546 /********************************************************************
00547  _RecordPertinentChildBicomp()
00548  Adds a child bicomp root into a vertex's pertinent bicomp list.
00549  ********************************************************************/
00550 void _RecordPertinentChildBicomp (graphP theGraph,
00551                                   int I,
00552                                   int RootVertex)
00553 {
00554   int ParentCopy,
00555     DFSChild,
00556     RootId,
00557     BicompList;
00558 
00559   /* The endpoints of the bicomp's root edge are the BicompRoot and a DFS Child
00560    * of the parent copy of the bicomp root. 
00561    * NOTE: The location of the root vertices is in the range N to 2N-1 at an
00562    * offset indicated by the DFS child with which it is associated */
00563   DFSChild = RootId = RootVertex - theGraph->N;
00564   ParentCopy = theGraph->V[DFSChild].DFSParent;
00565 
00566   /* Get the BicompList of the parent copy vertex. */
00567   BicompList = theGraph->V[ParentCopy].pertinentBicompList;
00568 
00569   /* Put the new root vertex in the BicompList.  It is prepended if internally
00570    * active and appended if externally active so that all internally
00571    * active bicomps are processed before any externally active bicomps
00572    * by virtue of storage.
00573    * 
00574    * NOTE: The activity status of a bicomp is computed using the lowpoint of
00575    * the DFS child in the bicomp's root edge because we want to know
00576    * whether the DFS child or any of its descendants are joined by a
00577    * back edge to ancestors of I. If so, then the bicomp rooted
00578    * at RootVertex must contain an externally active vertex so the
00579    * bicomp must be kept on the external face. */
00580   if (theGraph->V[DFSChild].Lowpoint < I)
00581     BicompList = LCAppend (theGraph->BicompLists, BicompList, RootId);
00582 
00583   else
00584     BicompList = LCPrepend (theGraph->BicompLists, BicompList, RootId);
00585 
00586   /* The head node of the parent copy vertex's bicomp list may have changed, so
00587    * we assign the head of the modified list as the vertex's pertinent
00588    * bicomp list */
00589   theGraph->V[ParentCopy].pertinentBicompList = BicompList;
00590 }
00591 
00592 
00593 /********************************************************************
00594  _WalkUp()
00595  I is the vertex currently being embedded
00596  J is the forward arc to the descendant W on which the Walkup begins
00597  
00598  The Walkup establishes pertinence for step I.  It marks W as 
00599  'adjacentTo' I so that the Walkdown will embed an edge to W when
00600  it is encountered.  
00601  
00602  The Walkup also determines the pertinent child bicomps that should be
00603  set up as a result of the need to embed edge (I, W). It does this by 
00604  recording the pertinent child biconnected components of all cut 
00605  vertices between W and the child of I that is a descendant of W.
00606  Note that it stops the traversal if it finds a visited flag set to I,
00607  which indicates that a prior walkup call in step I has already done
00608  the work.
00609 
00610  Zig and Zag are so named because one goes around one side of a
00611  bicomp and the other goes around the other side, yet we have
00612  as yet no notion of orientation for the bicomp.
00613  The edge J from vertex I gestures to an adjacent descendant vertex W
00614  (possibly in some other bicomp).  Zig and Zag start out at W.
00615  They go around alternate sides of the bicomp until its root is found.
00616  Recall that the root vertex is just a copy in region N to 2N-1.
00617  We want to hop from the root copy to the parent copy of the vertex
00618  in order to record which bicomp we just came from and also to continue
00619  the walk-up to vertex I.
00620  If the parent copy actually is I, then the walk-up is done.
00621  ********************************************************************/
00622 void _WalkUp (graphP theGraph,
00623               int I,
00624               int J)
00625 {
00626   int Zig,
00627     Zag,
00628     ZigPrevLink,
00629     ZagPrevLink;
00630   int N,
00631     R,
00632     ParentCopy,
00633     nextVertex,
00634     W;
00635   W = theGraph->G[J].v;
00636   theGraph->V[W].adjacentTo = J;
00637 
00638   /* Shorthand for N, due to frequent use */
00639   N = theGraph->N;
00640 
00641   /* Start at the vertex W and walk around the both sides of the external face
00642    * of a bicomp until we get back to vertex I. */
00643   Zig = Zag = W;
00644   ZigPrevLink = 1;
00645   ZagPrevLink = 0;
00646   while (Zig != I)
00647 
00648   {
00649 
00650     /* A previous walk-up may have been this way already */
00651     if (theGraph->G[Zig].visited == I)
00652       break;
00653     if (theGraph->G[Zag].visited == I)
00654       break;
00655 
00656     /* Mark the current vertices as visited during the embedding of vertex I. */
00657     theGraph->G[Zig].visited = I;
00658     theGraph->G[Zag].visited = I;
00659 
00660     /* Determine whether either Zig or Zag has landed on a bicomp root */
00661     if (Zig >= N)
00662       R = Zig;
00663 
00664     else if (Zag >= N)
00665       R = Zag;
00666 
00667     else
00668       R = NIL;
00669 
00670     /* If we have a bicomp root, then we want to hop up to the parent copy and
00671      * record a pertinent child bicomp (except that we could but don't need
00672      * to record pertinent child bicomps when the parent copy is I). */
00673     if (R != NIL)
00674 
00675     {
00676       ParentCopy = theGraph->V[R - N].DFSParent;
00677       if (ParentCopy != I)
00678         _RecordPertinentChildBicomp (theGraph, I, R);
00679       Zig = Zag = ParentCopy;
00680       ZigPrevLink = 1;
00681       ZagPrevLink = 0;
00682     }
00683 
00684     /* If we did not encounter a bicomp root, then we continue traversing the
00685      * external face in both directions. */
00686 
00687     else
00688 
00689     {
00690       nextVertex = theGraph->extFace[Zig].link[1 ^ ZigPrevLink];
00691       ZigPrevLink = theGraph->extFace[nextVertex].link[0] == Zig ? 0 : 1;
00692       Zig = nextVertex;
00693       nextVertex = theGraph->extFace[Zag].link[1 ^ ZagPrevLink];
00694       ZagPrevLink = theGraph->extFace[nextVertex].link[0] == Zag ? 0 : 1;
00695       Zag = nextVertex;
00696     }
00697   }
00698 }
00699 
00700 
00701 /********************************************************************
00702  _WalkDown()
00703  Consider a circular shape with small circles and squares along its perimeter.
00704  The small circle at the top the root vertex of the bicomp.  The other small
00705  circles represent internally active vertices, and the squares represent
00706  externally active vertices.  The root vertex is a root copy of I, the
00707  vertex currently being processed.
00708 
00709  The Walkup previously marked all vertices adjacent to I by setting their
00710  adjacentTo flags.  Basically, we want to walkdown both the link[0] and 
00711  then the link[1] sides of the bicomp rooted at RootVertex, embedding edges
00712  between it and descendants of I with the adjacentTo flag set.  It is sometimes
00713  necessary to hop to child biconnected components in order to reach the desired
00714  vertices and, in such cases, the biconnected components are merged together
00715  such that adding the back edge forms a new proper face in the biconnected
00716  component rooted at RootVertex (which, again, is a root copy of I).
00717 
00718  The outer loop performs both walks, unless the first walk got all the way
00719  around to RootVertex (only happens when bicomp contains no external activity,
00720  such as when processing the last vertex), or when non-planarity is 
00721  discovered (in a pertinent child bicomp such that the stack is non-empty).
00722 
00723  For the inner loop, each iteration visits a vertex W.  If W is adjacentTo I,
00724  we call MergeBicomps to merge the biconnected components whose cut vertices
00725  have been collecting in theStack.  Then, we add the back edge (RootVertex, W)
00726  and clear the adjacentTo flag in W.
00727 
00728  Next, we check whether W has a pertinent child bicomp.  If so, then we figure
00729  out which path down from the root of the child bicomp leads to the next vertex
00730  to be visited, and we push onto the stack information on the cut vertex and
00731  the paths used to enter into it and exit from it.  Alternately, if W
00732  had no pertinent child bicomps, then we check to see if it is inactive.
00733  If so, we find the next vertex along the external face, then short-circuit
00734  its inactive predecessor (under certain conditions).  Finally, if W is not 
00735  inactive, but it has no pertinent child bicomps, then we already know its 
00736  adjacentTo flag is clear so both criteria for internal activity also fail.  
00737  Therefore, W must be a stopping vertex.
00738 
00739  A stopping vertex X is an externally active vertex that has no pertinent
00740  child bicomps and no unembedded back edge to the current vertex I.
00741  The inner loop of Walkdown stops walking when it reaches a stopping vertex X 
00742  because if it were to proceed beyond X and embed a back edge, then X would be 
00743  surrounded by the bounding cycle of the bicomp.  This is clearly incorrect 
00744  because X has a path leading from it to an ancestor of I (which is why it's 
00745  externally active), and this path would have to cross the bounding cycle.
00746 
00747  After the loop, if the stack is non-empty, then the Walkdown halted because
00748  it could not proceed down a pertinent child biconnected component along either
00749  path from its root, which is easily shown to be evidence of a K_3,3, so
00750  we break the outer loop.  The caller performs further tests to determine
00751  whether Walkdown has embedded all back edges.  If the caller does not embed
00752  all back edges to descendants of the root vertex after walking both RootSide 
00753  0 then 1 in all bicomps containing a root copy of I, then the caller can 
00754  conclude that the input graph is non-planar.
00755  ********************************************************************/
00756 void _WalkDown (graphP theGraph,
00757                 int I,
00758                 int RootVertex)
00759 {
00760   int W,
00761     WPrevLink,
00762     R,
00763     Rout,
00764     X,
00765     XPrevLink,
00766     Y,
00767     YPrevLink,
00768     RootSide,
00769     RootEdgeChild;
00770   RootEdgeChild = RootVertex - theGraph->N;
00771   sp_ClearStack (theGraph->theStack);
00772   for (RootSide = 0; RootSide < 2; RootSide++)
00773 
00774   {
00775     WPrevLink = 1 ^ RootSide;
00776     W = theGraph->extFace[RootVertex].link[RootSide];
00777     while (W != RootVertex)
00778 
00779     {
00780 
00781       /* If the vertex is adjacent to vertex I, then merge bicomps at cut 
00782        * vertices on theStack and add the back edge.  This creates a 
00783        * proper face. Then, clear W's AdjacentTo flag so we don't add an 
00784        * edge to W if we visit it again later. */
00785       if (theGraph->V[W].adjacentTo != NIL)
00786 
00787       {
00788         _MergeBicomps (theGraph);
00789         _EmbedBackEdgeToDescendant (theGraph, RootSide, RootVertex, W,
00790                                     WPrevLink);
00791         theGraph->V[W].adjacentTo = NIL;
00792       }
00793 
00794       /* If there is a pertinent child bicomp, then we need to push it onto the stack
00795        * along with information about how we entered the cut vertex and how
00796        * we exit the root copy to get to the next vertex. */
00797       if (theGraph->V[W].pertinentBicompList != NIL)
00798 
00799       {
00800         sp_Push2 (theGraph->theStack, W, WPrevLink);
00801         R = _GetPertinentChildBicomp (theGraph, W);
00802 
00803         /* Get next active vertices X and Y on ext. face paths emanating from R */
00804         X = theGraph->extFace[R].link[0];
00805         XPrevLink = theGraph->extFace[X].link[1] == R ? 1 : 0;
00806         Y = theGraph->extFace[R].link[1];
00807         YPrevLink = theGraph->extFace[Y].link[0] == R ? 0 : 1;
00808 
00809         /* If this is a bicomp with only two ext. face vertices, then 
00810          * it could be that the orientation of the non-root vertex 
00811          * doesn't match the orientation of the root due to our relaxed 
00812          * orientation method. */
00813         if (X == Y && theGraph->extFace[X].inversionFlag)
00814 
00815         {
00816           XPrevLink = 0;
00817           YPrevLink = 1;
00818         }
00819 
00820         /* Now we implement the Walkdown's simple path selection rules!
00821          * If either X or Y is internally active (pertinent but not
00822          * externally active), then we pick it first.  Otherwise, 
00823          * we choose a pertinent vertex. If neither are pertinent,
00824          * then we pick a vertex since the next iteration of the
00825          * loop will terminate on that vertex with a non-empty stack. */
00826         if (_VertexActiveStatus (theGraph, X, I) == VAS_INTERNAL)
00827           W = X;
00828 
00829         else if (_VertexActiveStatus (theGraph, Y, I) == VAS_INTERNAL)
00830           W = Y;
00831 
00832         else if (PERTINENT (theGraph, X, I))
00833           W = X;
00834 
00835         else
00836           W = Y;
00837         WPrevLink = W == X ? XPrevLink : YPrevLink;
00838         Rout = W == X ? 0 : 1;
00839         sp_Push2 (theGraph->theStack, R, Rout);
00840       }
00841 
00842       /* Skip inactive vertices, which will be short-circuited
00843        * later by our fast external face linking method (once 
00844        * upon a time, we added false edges called short-circuit
00845        * edges to eliminate inactive vertices, but the extFace
00846        * links can do the same job and also give us the ability
00847        * to more quickly test planarity without creating an embedding). */
00848 
00849       else if (_VertexActiveStatus (theGraph, W, I) == VAS_INACTIVE)
00850 
00851       {
00852         X = theGraph->extFace[W].link[1 ^ WPrevLink];
00853         WPrevLink = theGraph->extFace[X].link[0] == W ? 0 : 1;
00854         W = X;
00855       }
00856 
00857       /* At this point, we know that W is not inactive, but its adjacentTo flag 
00858        * is clear, and it has no pertinent child bicomps.  Therefore, it
00859        * is an externally active stopping vertex. */
00860 
00861       else
00862         break;
00863     }
00864 
00865     /* We short-circuit the external face of the bicomp by hooking the root
00866      * to the terminating externally active vertex so that inactive vertices
00867      * are not visited in future iterations.  This setting obviates the need 
00868      * for those short-circuit edges mentioned above.
00869      * 
00870      * NOTE: We skip the step if the stack is non-empty since in that case
00871      * we did not actually merge the bicomps necessary to put
00872      * W and RootVertex into the same bicomp. */
00873     if (sp_IsEmpty (theGraph->theStack))
00874 
00875     {
00876       theGraph->extFace[RootVertex].link[RootSide] = W;
00877       theGraph->extFace[W].link[WPrevLink] = RootVertex;
00878 
00879       /* If the bicomp is reduced to having only two external face vertices
00880        * (the root and W), then we need to record whether the orientation
00881        * of W is inverted relative to the root.  This is used later when a 
00882        * future Walkdown descends to and merges the bicomp containing W.
00883        * Going from the root to W, we only get the correct WPrevLink if
00884        * we know whether or not W is inverted.
00885        * NOTE: Prior code based on short-circuit edges did not have this problem
00886        * because the root and W would be joined by two separate short-circuit
00887        * edges, so G[W].link[0] != G[W].link[1].
00888        * NOTE: We clear the flag because it may have been set in W if W 
00889        * previously became part of a bicomp with only two ext. face
00890        * vertices, but then was flipped and merged into a larger bicomp
00891        * that is now again becoming a bicomp with only two ext. face vertices. */
00892       if (theGraph->extFace[W].link[0] == theGraph->extFace[W].link[1]
00893           && WPrevLink == RootSide)
00894         theGraph->extFace[W].inversionFlag = 1;
00895 
00896       else
00897         theGraph->extFace[W].inversionFlag = 0;
00898     }
00899 
00900     /* If the stack is non-empty, then we had a non-planarity condition,
00901      * so we stop.  If we got back around to the root, then all edges
00902      * are embedded, so we stop. */
00903     if (sp_NonEmpty (theGraph->theStack) || W == RootVertex)
00904       break;
00905   }
00906 }
00907 
00908 
00909 /********************************************************************
00910  gp_Embed()
00911 
00912  return OK if the embedding was successfully created.
00913 
00914         NOTOK on internal failure
00915 
00916         NONEMBEDDABLE if the planar embedding couldn't be created due to
00917                 crossing edges, and theGraph receives a Kuratowski 
00918                 subgraph (a.k.a. planar obstruction).
00919  ********************************************************************/
00920 int gp_Embed (graphP theGraph,
00921               int embedFlags)
00922 {
00923   int N,
00924     I,
00925     J,
00926     child,
00927     RetVal = NOTOK;
00928 
00929   /* Basic parameter checks */
00930   if (theGraph == NULL)
00931     return NOTOK;
00932   if (embedFlags != 0 && embedFlags != EMBEDFLAGS_PLANAR)
00933     return NOTOK;
00934 
00935   /* A little shorthand for the size of the graph */
00936   N = theGraph->N;
00937 
00938   /* Preprocessing */
00939   theGraph->embedFlags = embedFlags;
00940   if (gp_CreateDFSTree (theGraph) != OK)
00941     return NOTOK;
00942   if (!(theGraph->internalFlags & FLAGS_SORTEDBYDFI))
00943     if (gp_SortVertices (theGraph) != OK)
00944       return NOTOK;
00945   gp_LowpointAndLeastAncestor (theGraph);
00946   _CreateSortedSeparatedDFSChildLists (theGraph);
00947   _CreateFwdArcLists (theGraph);
00948   _CreateDFSTreeEmbedding (theGraph);
00949 
00950   /* In reverse DFI order, process each vertex by embedding its
00951    * the 'back edges' from the vertex to its DFS descendants. */
00952   _FillVisitedFlags (theGraph, N);
00953   for (I = theGraph->N - 1; I >= 0; I--)
00954 
00955   {
00956     RetVal = OK;
00957 
00958     /* Do the Walkup for each cycle edge from I to a DFS descendant W. */
00959     J = theGraph->V[I].fwdArcList;
00960     while (J != NIL)
00961 
00962     {
00963       _WalkUp (theGraph, I, J);
00964       J = theGraph->G[J].link[0];
00965       if (J == theGraph->V[I].fwdArcList)
00966         J = NIL;
00967     }
00968 
00969     /* For each DFS child C of the current vertex with a pertinent
00970      * child bicomp, do a Walkdown on each side of the bicomp rooted 
00971      * by tree edge (R, C), where R is a root copy of the current 
00972      * vertex stored at C+N and uniquely associated with the bicomp 
00973      * containing C. (NOTE: if C has no pertinent child bicomps, then
00974      * there are no cycle edges from I to descendants of C). */
00975     child = theGraph->V[I].separatedDFSChildList;
00976     while (child != NIL)
00977 
00978     {
00979       if (theGraph->V[child].pertinentBicompList != NIL)
00980         _WalkDown (theGraph, I, child + N);
00981       child =
00982         LCGetNext (theGraph->DFSChildLists,
00983                    theGraph->V[I].separatedDFSChildList, child);
00984     }
00985 
00986     /* If all Walkdown calls succeed, but they don't embed all of the
00987      * forward edges, then the graph is non-planar. */
00988     if (theGraph->V[I].fwdArcList != NIL)
00989 
00990     {
00991       RetVal = NONEMBEDDABLE;
00992       break;
00993     }
00994   }
00995 
00996   /* Post-process the embedding structure if an embedding was
00997    * created to give a consistent orientation to all vertices. */
00998   if (RetVal == OK)
00999 
01000   {
01001     _OrientVerticesInEmbedding (theGraph);
01002     _JoinBicomps (theGraph);
01003   }
01004 
01005   else if (RetVal == NONEMBEDDABLE)
01006     _IsolateKuratowskiSubgraph (theGraph, I);
01007 
01008   /* Return indication of whether the graph is planar or non-planar. */
01009   return RetVal;
01010 }
01011 
01012 
01013 /********************************************************************
01014  _OrientVerticesInEmbedding()
01015 
01016  Each vertex will then have an orientation, either clockwise or
01017  counterclockwise.  All vertices in each bicomp need to have the
01018  same orientation.
01019  ********************************************************************/
01020 void _OrientVerticesInEmbedding (graphP theGraph)
01021 {
01022   int R,
01023     N;
01024   N = theGraph->N;
01025   sp_ClearStack (theGraph->theStack);
01026 
01027 /* Run the array of root copy vertices.  For each that is not defunct 
01028         (i.e. has not been merged during embed), we orient the vertices 
01029         in the bicomp for which it is the root vertex. */
01030   for (R = N; R < 2 * N; R++)
01031     if (theGraph->G[R].link[0] != NIL)
01032       _OrientVerticesInBicomp (theGraph, R, 0);
01033 }
01034 
01035 
01036 /********************************************************************
01037  _OrientVerticesInBicomp()
01038   As a result of the work done so far, the edges around each vertex have
01039  been put in order, but the orientation may be counterclockwise or
01040  clockwise for different vertices within the same bicomp.
01041  We need to reverse the orientations of those vertices that are not
01042  oriented the same way as the root of the bicomp.
01043 
01044  During embedding, a bicomp with root edge (v', c) may need to be flipped.
01045  We do this by inverting the root copy v' and implicitly inverting the
01046  orientation of the vertices in the subtree rooted by c by assigning -1
01047  to the sign of the DFSCHILD edge record leading to c.
01048 
01049  We now use these signs to help propagate a consistent vertex orientation
01050  throughout all vertices that have been merged into the given bicomp.
01051  The bicomp root contains the orientation to be imposed on all parent
01052  copy vertices.  We perform a standard depth first search to visit each
01053  vertex.  A vertex must be inverted if the product of the edge signs
01054  along the tree edges between the bicomp root and the vertex is -1.
01055 
01056  Finally, the PreserveSigns flag, if set, performs the inversions
01057  but does not change any of the edge signs.  This allows a second
01058  invocation of this function to restore the state of the bicomp
01059  as it was before the first call.
01060  ********************************************************************/
01061 void _OrientVerticesInBicomp (graphP theGraph,
01062                               int BicompRoot,
01063                               int PreserveSigns)
01064 {
01065   int V,
01066     J,
01067     curSign;
01068   sp_Push2 (theGraph->theStack, BicompRoot, 1);
01069   while (sp_NonEmpty (theGraph->theStack))
01070 
01071   {
01072 
01073     /* Pop a vertex to orient */
01074     sp_Pop2 (theGraph->theStack, V, curSign);
01075 
01076     /* Invert the vertex if the sign is -1 */
01077     if (curSign == -1)
01078       _InvertVertex (theGraph, V);
01079 
01080     /* Push the vertex's DFS children that are in the bicomp */
01081     J = theGraph->G[V].link[0];
01082     while (J >= 2 * theGraph->N)
01083 
01084     {
01085       if (theGraph->G[J].type == EDGE_DFSCHILD)
01086 
01087       {
01088         sp_Push2 (theGraph->theStack, theGraph->G[J].v,
01089                   curSign * theGraph->G[J].sign);
01090         if (!PreserveSigns)
01091           theGraph->G[J].sign = 1;
01092       }
01093       J = theGraph->G[J].link[0];
01094     }
01095   }
01096 }
01097 
01098 
01099 /********************************************************************
01100  _JoinBicomps()
01101  The embedding algorithm works by only joining bicomps once the result
01102  forms a larger bicomp.  However, if the original graph was separable
01103  or disconnected, then the result of the embed function will be a
01104  graph that contains each bicomp as a distinct entity.  The root of
01105  each bicomp will be in the region N to 2N-1.  This function merges
01106  the bicomps into one connected graph.
01107  ********************************************************************/
01108 int _JoinBicomps (graphP theGraph)
01109 {
01110   int R,
01111     N;
01112   for (R = N = theGraph->N; R < 2 * N; R++)
01113     if (theGraph->G[R].link[0] != NIL)
01114       _MergeVertex (theGraph, theGraph->V[R - N].DFSParent, 0, R);
01115   return OK;
01116 }

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