int _K33Search_MergeBicomps(graphP theGraph, int v, int RootVertex, int W, int WPrevLink) { K33SearchContext *context = NULL; gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context); if (context != NULL) { /* If the merge is blocked, then a K_{3,3} homeomorph is isolated, and NONEMBEDDABLE is returned so that the Walkdown terminates */ if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK33) { int mergeBlocker; // We want to test all merge points on the stack // as well as W, since the connection will go // from W. So we push W as a 'degenerate' merge point. sp_Push2(theGraph->theStack, W, WPrevLink); sp_Push2(theGraph->theStack, NIL, NIL); if (_SearchForMergeBlocker(theGraph, context, v, &mergeBlocker) != OK) return NOTOK; if (gp_IsVertex(mergeBlocker)) { if (_FindK33WithMergeBlocker(theGraph, context, v, mergeBlocker) != OK) return NOTOK; return NONEMBEDDABLE; } // If no merge blocker was found, then remove W from the stack. sp_Pop2(theGraph->theStack, W, WPrevLink); sp_Pop2(theGraph->theStack, W, WPrevLink); } // If the merge was not blocked, then we perform the merge // When not doing a K3,3 search, then the merge is not // blocked as far as the K3,3 search method is concerned // Another algorithms could overload MergeBicomps and block // merges under certain conditions, but those would be based // on data maintained by the extension that implements the // other algorithm-- if *that* algorithm is the one being run return context->functions.fpMergeBicomps(theGraph, v, RootVertex, W, WPrevLink); } return NOTOK; }
int _FindNonplanarityBicompRoot(graphP theGraph) { int R, tempChild, fwdArc, W=NIL, C=NIL, I=theGraph->IC.v; /* If the stack is non-empty, then the Walkdown stopped on a descendant bicomp, not one rooted by I. We need to get that root before the stack is destroyed by other routines. */ if (sp_NonEmpty(theGraph->theStack)) { int e; sp_Pop2(theGraph->theStack, R, e); return R; } /* Obtain the forward arc of an unembedded back edge from I to one of its descendants (edges are removed from the forward arc list as they are embedded, so the list will be empty if all edges were embedded). */ if ((fwdArc = theGraph->V[I].fwdArcList) == NIL) return NIL; W = theGraph->G[fwdArc].v; /* Find the greatest DFS child C of I that is less than W. This will give us the ancestor of W that is a child of I. Since the ancestors of I have not been processed by the planarity algorithm, the separatedDFSChildList of I contains all the children of I. */ tempChild = theGraph->V[I].separatedDFSChildList; while (tempChild != NIL) { if (tempChild > C && tempChild < W) C = tempChild; tempChild = LCGetNext(theGraph->DFSChildLists, theGraph->V[I].separatedDFSChildList, tempChild); } if (C == NIL) return NIL; /* The root vertex of a bicomp rooted by edge (I, C) is located at position C+N in our data structures */ R = C + theGraph->N; return R; }
int _K4Search_HandleBlockedBicomp(graphP theGraph, int v, int RootVertex, int R) { K4SearchContext *context = NULL; gp_FindExtension(theGraph, K4SEARCH_ID, (void *)&context); if (context == NULL) return NOTOK; if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK4) { int RetVal = OK; // If invoked on a descendant bicomp, then we push its root then search once // since not finding a K4 homeomorph will also clear the blockage and allow // the Walkdown to continue walking down if (R != RootVertex) { sp_Push2(theGraph->theStack, R, 0); if ((RetVal = _SearchForK4InBicomp(theGraph, context, v, R)) == OK) { // If the Walkdown will be told it is OK to continue, then we have to take the descendant // bicomp root back off the stack so the Walkdown can try to descend to it again. int dummy; sp_Pop2(theGraph->theStack, R, dummy); // And we have to clear the indicator of the minor A that was reduced, since it was eliminated. theGraph->IC.minorType = 0; } } // Otherwise, if invoked on a child bicomp rooted by a virtual copy of v, // then we search for a K4 homeomorph, and if OK is returned, then that indicates // the blockage has been cleared and it is OK to Walkdown the bicomp. // But the Walkdown finished, already, so we launch it again. // If the Walkdown returns OK then all forward arcs were embedded. If NONEMBEDDABLE // is returned, then the bicomp got blocked again, so we have to reiterate the K4 search else { // If Walkdown has recursively called this handler on the bicomp rooted by RootVertex, // then it is still blocked, so we just return NONEMBEDDABLE, which causes Walkdown to // return to the loop below and signal that the loop should invoke the Walkdown again. if (context->handlingBlockedBicomp) return NONEMBEDDABLE; context->handlingBlockedBicomp = TRUE; do { // Detect whether bicomp can be used to find a K4 homeomorph. It it does, then // it returns NONEMBEDDABLE so we break the search because we found the desired K4 // If OK is returned, then the blockage was cleared and it is OK to Walkdown again. if ((RetVal = _SearchForK4InBicomp(theGraph, context, v, RootVertex)) != OK) break; // Walkdown again to embed more edges. If Walkdown returns OK, then all remaining // edges to its descendants are embedded, so we'll get out of this loop. If Walkdown // detects that it still has not embedded all the edges to descendants of the bicomp's // root edge child, then Walkdown calls this routine again, and the above non-reentrancy // code returns NONEMBEDDABLE, causing this loop to search again for a K4. theGraph->IC.minorType = 0; RetVal = theGraph->functions.fpWalkDown(theGraph, v, RootVertex); // Except if the Walkdown returns NONEMBEDDABLE due to finding a K4 homeomorph entangled // with a descendant bicomp (the R != RootVertex case above), then it was found // entangled with Minor A, so we can stop the search if minor A is detected if (theGraph->IC.minorType & MINORTYPE_A) break; } while (RetVal == NONEMBEDDABLE); context->handlingBlockedBicomp = FALSE; } return RetVal; } else { return context->functions.fpHandleBlockedBicomp(theGraph, v, RootVertex, R); } return NOTOK; }
int gp_CreateDFSTree(graphP theGraph) { stackP theStack; int N, DFI = 0, I, uparent, u, e, J; #ifdef PROFILE platform_time start, end; platform_GetTime(start); #endif if (theGraph==NULL) return NOTOK; if (theGraph->internalFlags & FLAGS_DFSNUMBERED) return OK; gp_LogLine("\ngraphPreprocess.c/gp_CreateDFSTree() start"); N = theGraph->N; theStack = theGraph->theStack; /* There are 2M edge records (arcs) and for each we can push 2 integers, so a stack of 2 * arcCapacity integers suffices. This is already in theGraph structure, so we make sure it's empty, then clear all visited flags in prep for the Depth first search. */ if (sp_GetCapacity(theStack) < 2*gp_GetArcCapacity(theGraph)) return NOTOK; sp_ClearStack(theStack); for (I=0; I < N; I++) theGraph->G[I].visited = 0; /* This outer loop causes the connected subgraphs of a disconnected graph to be numbered */ for (I=0; I < N && DFI < N; I++) { if (theGraph->V[I].DFSParent != NIL) continue; sp_Push2(theStack, NIL, NIL); while (sp_NonEmpty(theStack)) { sp_Pop2(theStack, uparent, e); u = uparent == NIL ? I : theGraph->G[e].v; if (!theGraph->G[u].visited) { gp_LogLine(gp_MakeLogStr3("V=%d, DFI=%d, Parent=%d", u, DFI, uparent)); theGraph->G[u].visited = 1; theGraph->G[u].v = DFI++; theGraph->V[u].DFSParent = uparent; if (e != NIL) { theGraph->G[e].type = EDGE_DFSCHILD; theGraph->G[gp_GetTwinArc(theGraph, e)].type = EDGE_DFSPARENT; // We want the child arcs to be at the beginning // of the adjacency list. gp_MoveArcToFirst(theGraph, uparent, e); } /* Push edges to all unvisited neighbors. These will be either tree edges to children or forward arcs of back edges */ J = gp_GetFirstArc(theGraph, u); while (gp_IsArc(theGraph, J)) { if (!theGraph->G[theGraph->G[J].v].visited) sp_Push2(theStack, u, J); J = gp_GetNextArc(theGraph, J); } } else { // If the edge leads to a visited vertex, then it is // the forward arc of a back edge. theGraph->G[e].type = EDGE_FORWARD; theGraph->G[gp_GetTwinArc(theGraph, e)].type = EDGE_BACK; // We want all of the forward edges to descendants to // be at the end of the adjacency list. // The tree edge to the parent and the back edges to ancestors // are in the middle, between the child edges and forward edges. gp_MoveArcToLast(theGraph, uparent, e); } } } gp_LogLine("graphPreprocess.c/gp_CreateDFSTree() end\n"); theGraph->internalFlags |= FLAGS_DFSNUMBERED; #ifdef PROFILE platform_GetTime(end); printf("DFS in %.3lf seconds.\n", platform_GetDuration(start,end)); #endif return OK; }