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 }