void _K33Search_EmbedBackEdgeToDescendant(graphP theGraph, int RootSide, int RootVertex, int W, int WPrevLink) { K33SearchContext *context = NULL; gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context); if (context != NULL) { // K33 search may have been attached, but not enabled if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK33) { // Get the fwdArc from the adjacentTo field, and use it to get the backArc int backArc = gp_GetTwinArc(theGraph, gp_GetVertexPertinentEdge(theGraph, W)); // Remove the backArc from the backArcList if (context->VI[W].backArcList == backArc) { if (gp_GetNextArc(theGraph, backArc) == backArc) context->VI[W].backArcList = NIL; else context->VI[W].backArcList = gp_GetNextArc(theGraph, backArc); } gp_SetNextArc(theGraph, gp_GetPrevArc(theGraph, backArc), gp_GetNextArc(theGraph, backArc)); gp_SetPrevArc(theGraph, gp_GetNextArc(theGraph, backArc), gp_GetPrevArc(theGraph, backArc)); } // Invoke the superclass version of the function context->functions.fpEmbedBackEdgeToDescendant(theGraph, RootSide, RootVertex, W, WPrevLink); } }
int _DeleteUnmarkedVerticesAndEdges(graphP theGraph) { int v, e; /* All of the forward and back arcs of all of the edge records were removed from the adjacency lists in the planarity algorithm preprocessing. We now put them back into the adjacency lists (and we do not mark them), so they can be properly deleted below. */ for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v); v++) { while (gp_IsArc(e = gp_GetVertexFwdArcList(theGraph, v))) _AddBackEdge(theGraph, v, gp_GetNeighbor(theGraph, e)); } /* Now we delete all unmarked edges. We don't delete vertices from the embedding, but the ones we should delete will become degree zero. */ for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v); v++) { e = gp_GetFirstArc(theGraph, v); while (gp_IsArc(e)) { if (gp_GetEdgeVisited(theGraph, e)) e = gp_GetNextArc(theGraph, e); else e = gp_DeleteEdge(theGraph, e, 0); } } return OK; }
int _GetContractibleNeighbors(ColorVerticesContext *context, int v, int *pu, int *pw) { int lowDegreeNeighbors[5], i, j, n=0, J; graphP theGraph = context->theGraph; // This method is only applicable to degree 5 vertices if (_GetVertexDegree(context, v) != 5) return FALSE; // Get all neighbors of degree at most 7 J = gp_GetFirstArc(theGraph, v); while (gp_IsArc(theGraph, J)) { if (_GetVertexDegree(context, theGraph->G[J].v) <= 7) lowDegreeNeighbors[n++] = theGraph->G[J].v; J = gp_GetNextArc(theGraph, J); } // Seek the pair of *non-adjacent* low degree neighbors for (i=0; i < (n-1); i++) for (j=i+1; j < n; j++) if (!gp_IsNeighbor(theGraph, lowDegreeNeighbors[i], lowDegreeNeighbors[j])) { *pu = lowDegreeNeighbors[i]; *pw = lowDegreeNeighbors[j]; return TRUE; } // The desired pair of neighbors was not found return FALSE; }
int gp_ColorVerticesIntegrityCheck(graphP theGraph, graphP origGraph) { int I, J, w; ColorVerticesContext *context = (ColorVerticesContext *) gp_GetExtension(theGraph, COLORVERTICES_ID); if (theGraph == NULL || origGraph == NULL || context == NULL) return NOTOK; if (gp_GetNumColorsUsed(theGraph) <= 0 && theGraph->M > 0) return NOTOK; if (_TestSubgraph(theGraph, origGraph) != TRUE) return NOTOK; if (_TestSubgraph(origGraph, theGraph) != TRUE) return NOTOK; for (I=0; I < theGraph->N; I++) { J = gp_GetFirstArc(theGraph, I); while (gp_IsArc(theGraph, J)) { w = theGraph->G[J].v; if (context->color[I] < 0 || context->color[I] == context->color[w]) return NOTOK; J = gp_GetNextArc(theGraph, J); } } return OK; }
int gp_ColorVerticesIntegrityCheck(graphP theGraph, graphP origGraph) { int v, w, e; ColorVerticesContext *context = (ColorVerticesContext *) gp_GetExtension(theGraph, COLORVERTICES_ID); if (theGraph == NULL || origGraph == NULL || context == NULL) return NOTOK; if (gp_GetNumColorsUsed(theGraph) <= 0 && theGraph->M > 0) return NOTOK; if (_TestSubgraph(theGraph, origGraph) != TRUE) return NOTOK; if (_TestSubgraph(origGraph, theGraph) != TRUE) return NOTOK; for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v); v++) { e = gp_GetFirstArc(theGraph, v); while (gp_IsArc(e)) { w = gp_GetNeighbor(theGraph, e); if (context->color[v] < 0 || context->color[v] == context->color[w]) return NOTOK; e = gp_GetNextArc(theGraph, e); } } return OK; }
void _AddBackEdge(graphP theGraph, int ancestor, int descendant) { int fwdArc, backArc; /* We get the two edge records of the back edge to embed. */ fwdArc = gp_GetVertexFwdArcList(theGraph, ancestor); while (gp_IsArc(fwdArc)) { if (gp_GetNeighbor(theGraph, fwdArc) == descendant) break; fwdArc = gp_GetNextArc(theGraph, fwdArc); if (fwdArc == gp_GetVertexFwdArcList(theGraph, ancestor)) fwdArc = NIL; } if (gp_IsNotArc(fwdArc)) return; backArc = gp_GetTwinArc(theGraph, fwdArc); /* The forward arc is removed from the fwdArcList of the ancestor. */ if (gp_GetVertexFwdArcList(theGraph, ancestor) == fwdArc) { if (gp_GetNextArc(theGraph, fwdArc) == fwdArc) gp_SetVertexFwdArcList(theGraph, ancestor, NIL); else gp_SetVertexFwdArcList(theGraph, ancestor, gp_GetNextArc(theGraph, fwdArc)); } gp_SetNextArc(theGraph, gp_GetPrevArc(theGraph, fwdArc), gp_GetNextArc(theGraph, fwdArc)); gp_SetPrevArc(theGraph, gp_GetNextArc(theGraph, fwdArc), gp_GetPrevArc(theGraph, fwdArc)); /* The forward arc is added to the adjacency list of the ancestor. */ gp_SetPrevArc(theGraph, fwdArc, NIL); gp_SetNextArc(theGraph, fwdArc, gp_GetFirstArc(theGraph, ancestor)); gp_SetPrevArc(theGraph, gp_GetFirstArc(theGraph, ancestor), fwdArc); gp_SetFirstArc(theGraph, ancestor, fwdArc); /* The back arc is added to the adjacency list of the descendant. */ gp_SetPrevArc(theGraph, backArc, NIL); gp_SetNextArc(theGraph, backArc, gp_GetFirstArc(theGraph, descendant)); gp_SetPrevArc(theGraph, gp_GetFirstArc(theGraph, descendant), backArc); gp_SetFirstArc(theGraph, descendant, backArc); gp_SetNeighbor(theGraph, backArc, ancestor); }
void _AddBackEdge(graphP theGraph, int ancestor, int descendant) { int fwdArc, backArc; /* We get the two edge records of the back edge to embed. */ fwdArc = theGraph->V[ancestor].fwdArcList; while (gp_IsArc(theGraph, fwdArc)) { if (theGraph->G[fwdArc].v == descendant) break; fwdArc = gp_GetNextArc(theGraph, fwdArc); if (fwdArc == theGraph->V[ancestor].fwdArcList) fwdArc = NIL; } if (fwdArc == NIL) return; backArc = gp_GetTwinArc(theGraph, fwdArc); /* The forward arc is removed from the fwdArcList of the ancestor. */ if (theGraph->V[ancestor].fwdArcList == fwdArc) { if (gp_GetNextArc(theGraph, fwdArc) == fwdArc) theGraph->V[ancestor].fwdArcList = NIL; else theGraph->V[ancestor].fwdArcList = gp_GetNextArc(theGraph, fwdArc); } gp_SetNextArc(theGraph, gp_GetPrevArc(theGraph, fwdArc), gp_GetNextArc(theGraph, fwdArc)); gp_SetPrevArc(theGraph, gp_GetNextArc(theGraph, fwdArc), gp_GetPrevArc(theGraph, fwdArc)); /* The forward arc is added to the adjacency list of the ancestor. */ gp_SetPrevArc(theGraph, fwdArc, gp_AdjacencyListEndMark(ancestor)); gp_SetNextArc(theGraph, fwdArc, gp_GetFirstArc(theGraph, ancestor)); gp_SetPrevArc(theGraph, gp_GetFirstArc(theGraph, ancestor), fwdArc); gp_SetFirstArc(theGraph, ancestor, fwdArc); /* The back arc is added to the adjacency list of the descendant. */ gp_SetPrevArc(theGraph, backArc, gp_AdjacencyListEndMark(descendant)); gp_SetNextArc(theGraph, backArc, gp_GetFirstArc(theGraph, descendant)); gp_SetPrevArc(theGraph, gp_GetFirstArc(theGraph, descendant), backArc); gp_SetFirstArc(theGraph, descendant, backArc); theGraph->G[backArc].v = ancestor; }
/**************************************************************************** _MarkDFSPath() Sets visited flags of vertices and edges from descendant to ancestor, including root copy vertices, and including the step of hopping from a root copy to its parent copy. At each vertex, the edge record is obtained whose type indicates that it leads to the DFS parent. An earlier implementation just used the DFS parent member of the vertex, but then had to find the edge to mark anyway. This method is more generalized because some extension algorithms reduce DFS paths to single DFS tree edges, in which case the edge record with type EDGE_TYPE_PARENT may indicate the DFS paent or an ancestor. ****************************************************************************/ int _MarkDFSPath(graphP theGraph, int ancestor, int descendant) { int e, parent; // If we are marking from a root (virtual) vertex upward, then go up to the parent // copy before starting the loop if (gp_IsVirtualVertex(theGraph, descendant)) descendant = gp_GetPrimaryVertexFromRoot(theGraph, descendant); // Mark the lowest vertex (the one with the highest number). gp_SetVertexVisited(theGraph, descendant); // Mark all ancestors of the lowest vertex, and the edges used to reach // them, up to the given ancestor vertex. while (descendant != ancestor) { if (gp_IsNotVertex(descendant)) return NOTOK; // If we are at a bicomp root, then ascend to its parent copy and // mark it as visited. if (gp_IsVirtualVertex(theGraph, descendant)) { parent = gp_GetPrimaryVertexFromRoot(theGraph, descendant); } // If we are on a regular, non-virtual vertex then get the edge to the parent, // mark the edge, then fall through to the code that marks the parent vertex. else { // Scan the edges for the one marked as the DFS parent parent = NIL; e = gp_GetFirstArc(theGraph, descendant); while (gp_IsArc(e)) { if (gp_GetEdgeType(theGraph, e) == EDGE_TYPE_PARENT) { parent = gp_GetNeighbor(theGraph, e); break; } e = gp_GetNextArc(theGraph, e); } // Sanity check on the data structure integrity if (gp_IsNotVertex(parent)) return NOTOK; // Mark the edge gp_SetEdgeVisited(theGraph, e); gp_SetEdgeVisited(theGraph, gp_GetTwinArc(theGraph, e)); } // Mark the parent, then hop to the parent and reiterate gp_SetVertexVisited(theGraph, parent); descendant = parent; } return OK; }
int _MarkDFSPath(graphP theGraph, int ancestor, int descendant) { int J, parent, Z, N; N = theGraph->N; /* If we are marking from a root vertex upward, then go up to the parent copy before starting the loop */ if (descendant >= N) descendant = theGraph->V[descendant-N].DFSParent; /* Mark the lowest vertex (i.e. the descendant with the highest number) */ theGraph->G[descendant].visited = 1; /* Mark all ancestors of the lowest vertex, and the edges used to reach them, up to the given ancestor vertex. */ while (descendant != ancestor) { /* Get the parent vertex */ parent = theGraph->V[descendant].DFSParent; /* If the descendant was a DFS tree root, then obviously we aren't going to find the ancestor, so something is wrong.*/ if (parent == NIL || parent == descendant) return NOTOK; /* Find the edge from descendant that leads either to parent or to a root copy of the parent. When the edge is found, mark it and break the loop */ J = gp_GetFirstArc(theGraph, descendant); while (gp_IsArc(theGraph, J)) { Z = theGraph->G[J].v; if ((Z < N && Z == parent) || (Z >= N && theGraph->V[Z-N].DFSParent == parent)) { theGraph->G[J].visited = 1; theGraph->G[gp_GetTwinArc(theGraph, J)].visited = 1; break; } J = gp_GetNextArc(theGraph, J); } /* Mark the parent copy of the DFS parent */ theGraph->G[parent].visited = 1; /* Hop to the parent */ descendant = parent; } return OK; }
int _SearchForK23(graphP theGraph, int I) { int J, W, C, RetVal=OK; /* Traverse the edges of I to find the unembedded forward edges to descendants. For each such edge (I, W), traverse the DFS tree path up to mark the child of I that is the root of the subtree containing W. Optimize with visitation flag. */ /* Traverse each unembedded back edge to the descendant endpoint... */ J = theGraph->V[I].fwdArcList; // Ensure we have at least one bicomp on which Walkdown failed, which // should always be the case in an error free implementation if (!gp_IsArc(theGraph, J)) return NOTOK; while (J != NIL) { W = theGraph->G[J].v; /* Go from the descendant endpoint to find the ancestor that is a child of I, which in turn indicates the root of a bicomp on which the Walkdown failed to embed all back edges */ C = W; while (theGraph->V[C].DFSParent != I) C = theGraph->V[C].DFSParent; RetVal = _SearchForK23InBicomp(theGraph, I, C+theGraph->N); /* If something went wrong, NOTOK was returned; If a K_{2,3} was found, NONEMBEDDABLE was returned; If OK was returned, then an isolated K_4 was found, so we continue searching any other bicomps on which the Walkdown failed. */ if (RetVal != OK) break; /* Get the next unembedded back edge from I */ J = gp_GetNextArc(theGraph, J); if (J == theGraph->V[I].fwdArcList) J = NIL; } /* If we got through the loop with an OK value for each bicomp on which the Walkdown failed, then we return OK to indicate that only isolated K_4's were found. This allows the embedder to continue. If a K_{2,3} is ever found (or if an error occurred), then RetVal will not be OK, and the loop terminates immediately so we can return the appropriate value. */ return RetVal; }
int _AssignColorToVertex(ColorVerticesContext *context, graphP theGraph, int v) { int J, w, color; // Run the neighbor list of v and flag all the colors in use J = gp_GetFirstArc(theGraph, v); while (gp_IsArc(theGraph, J)) { w = theGraph->G[J].v; context->colorDetector[context->color[w]] = 1; J = gp_GetNextArc(theGraph, J); } // Find the least numbered unused color and assign it to v // Note that this loop never runs more than deg(v) steps for (color = 0; color < theGraph->N; color++) { if (context->colorDetector[color] == 0) { context->color[v] = color; if (context->highestColorUsed < color) context->highestColorUsed = color; break; } } if (context->color[v] < 0) return NOTOK; // Run the neighbor list of v and unflag all the colors in use J = gp_GetFirstArc(theGraph, v); while (gp_IsArc(theGraph, J)) { w = theGraph->G[J].v; context->colorDetector[context->color[w]] = 0; J = gp_GetNextArc(theGraph, J); } return OK; }
int _FindUnembeddedEdgeToSubtree(graphP theGraph, int ancestor, int SubtreeRoot, int *pDescendant) { int e, Z, ZNew; *pDescendant = NIL; /* If SubtreeRoot is a root copy, then we change to the DFS child in the DFS tree root edge of the bicomp rooted by SubtreeRoot. */ SubtreeRoot = gp_IsVirtualVertex(theGraph, SubtreeRoot) ? gp_GetDFSChildFromRoot(theGraph, SubtreeRoot) : SubtreeRoot; /* Find the least descendant of the cut vertex incident to the ancestor. */ e = gp_GetVertexFwdArcList(theGraph, ancestor); while (gp_IsArc(e)) { if (gp_GetNeighbor(theGraph, e) >= SubtreeRoot) { if (gp_IsNotVertex(*pDescendant) || *pDescendant > gp_GetNeighbor(theGraph, e)) *pDescendant = gp_GetNeighbor(theGraph, e); } e = gp_GetNextArc(theGraph, e); if (e == gp_GetVertexFwdArcList(theGraph, ancestor)) e = NIL; } if (gp_IsNotVertex(*pDescendant)) return FALSE; /* Make sure the identified descendant actually descends from the cut vertex */ Z = *pDescendant; while (Z != SubtreeRoot) { ZNew = gp_GetVertexParent(theGraph, Z); if (gp_IsNotVertex(ZNew) || ZNew == Z) return FALSE; Z = ZNew; } /* Return successfully */ return TRUE; }
int _FindUnembeddedEdgeToSubtree(graphP theGraph, int ancestor, int SubtreeRoot, int *pDescendant) { int J, Z, ZNew; *pDescendant = NIL; /* If SubtreeRoot is a root copy, then we change to the DFS child in the DFS tree root edge of the bicomp rooted by SubtreeRoot. */ if (SubtreeRoot >= theGraph->N) SubtreeRoot -= theGraph->N; /* Find the least descendant of the cut vertex incident to the ancestor. */ J = theGraph->V[ancestor].fwdArcList; while (gp_IsArc(theGraph, J)) { if (theGraph->G[J].v >= SubtreeRoot) { if (*pDescendant == NIL || *pDescendant > theGraph->G[J].v) *pDescendant = theGraph->G[J].v; } J = gp_GetNextArc(theGraph, J); if (J == theGraph->V[ancestor].fwdArcList) J = NIL; } if (*pDescendant == NIL) return FALSE; /* Make sure the identified descendant actually descends from the cut vertex */ Z = *pDescendant; while (Z != SubtreeRoot) { ZNew = theGraph->V[Z].DFSParent; if (ZNew == NIL || ZNew == Z) return FALSE; Z = ZNew; } /* Return successfully */ return TRUE; }
int _TestPath(graphP theGraph, int U, int V) { int e = gp_GetFirstArc(theGraph, U); while (gp_IsArc(e)) { if (_TryPath(theGraph, e, V) == OK) { _MarkPath(theGraph, e); return TRUE; } e = gp_GetNextArc(theGraph, e); } return FALSE; }
void _K33Search_CreateDFSTreeEmbedding(graphP theGraph) { K33SearchContext *context = NULL; gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context); if (context != NULL) { // When searching for K_{3,3} homeomorphs, we need the // list of DFS children for each vertex, which gets lost // during the initial tree embedding (each DFS tree child // arc is moved to the root copy of the vertex) if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK33) { int I, J, N; N = theGraph->N; for (I=0; I<N; I++) { J = gp_GetFirstArc(theGraph, I); // If a vertex has any DFS children, the edges // to them are stored in descending order of // the DFI's along the successor arc pointers, so // we traverse them and prepend each to the // ascending order sortedDFSChildList while (theGraph->G[J].type == EDGE_DFSCHILD) { context->V[I].sortedDFSChildList = LCPrepend(context->sortedDFSChildLists, context->V[I].sortedDFSChildList, theGraph->G[J].v); J = gp_GetNextArc(theGraph, J); } } } // Invoke the superclass version of the function context->functions.fpCreateDFSTreeEmbedding(theGraph); } }
int _ColorVertices_IdentifyVertices(graphP theGraph, int u, int v, int eBefore) { ColorVerticesContext *context = (ColorVerticesContext *) gp_GetExtension(theGraph, COLORVERTICES_ID); if (context != NULL) { int e_v_last, e_v_first; // First, identify u and v. No point in taking v's degree beforehand // because some of its incident edges may indicate neighbors of u. This // causes v to be moved to a lower degree list than deg(v). if (context->functions.fpIdentifyVertices(theGraph, u, v, eBefore) != OK) return NOTOK; // The edges transferred from v to u are indicated on the top of the // stack, which looks like this after identifying u and v: // ... e_u_succ e_v_last e_v_first e_u_pred u v e_v_first = sp_Get(theGraph->theStack, sp_GetCurrentSize(theGraph->theStack)-4); e_v_last = sp_Get(theGraph->theStack, sp_GetCurrentSize(theGraph->theStack)-5); // We count the number of edges K transferred from v to u after the // common edges were hidden if (gp_IsArc(theGraph, e_v_first)) { int J, K, degu; for (J=e_v_first, K=1; J != e_v_last; J=gp_GetNextArc(theGraph, J)) K++; // Remove v from the degree list K. During IdentifyVertices(), if v had any // common edges with u, they were "hidden", which reduced the degree of v to K. _RemoveVertexFromDegList(context, theGraph, v, K); // We move u from degree list deg(u)-K to degree list deg(u) degu = gp_GetVertexDegree(theGraph, u); _RemoveVertexFromDegList(context, theGraph, u, degu-K); _AddVertexToDegList(context, theGraph, u, degu); } return OK; } return NOTOK; }
void _MarkPath(graphP theGraph, int e) { int eTwin, nextVertex; nextVertex = gp_GetNeighbor(theGraph, e); // while nextVertex is strictly degree 2 while (gp_IsArc(gp_GetFirstArc(theGraph, nextVertex)) && gp_IsArc(gp_GetLastArc(theGraph, nextVertex)) && gp_GetNextArc(theGraph, gp_GetFirstArc(theGraph, nextVertex)) == gp_GetLastArc(theGraph, nextVertex)) { gp_SetVertexVisited(theGraph, nextVertex); eTwin = gp_GetTwinArc(theGraph, e); e = gp_GetFirstArc(theGraph, nextVertex); if (e == eTwin) e = gp_GetLastArc(theGraph, nextVertex); nextVertex = gp_GetNeighbor(theGraph, e); } }
int _WriteAdjMatrix(graphP theGraph, FILE *Outfile) { int I, J, K; char *Row = NULL; if (theGraph != NULL) Row = (char *) malloc((theGraph->N+1)*sizeof(char)); if (Row==NULL || theGraph==NULL || Outfile==NULL) { if (Row != NULL) free(Row); return NOTOK; } fprintf(Outfile, "%d\n", theGraph->N); for (I = 0; I < theGraph->N; I++) { for (K = 0; K <= I; K++) Row[K] = ' '; for (K = I+1; K < theGraph->N; K++) Row[K] = '0'; J = gp_GetFirstArc(theGraph, I); while (gp_IsArc(theGraph, J)) { if (gp_GetDirection(theGraph, J, EDGEFLAG_DIRECTION_INONLY)) return NOTOK; if (theGraph->G[J].v > I) Row[theGraph->G[J].v] = '1'; J = gp_GetNextArc(theGraph, J); } Row[theGraph->N] = '\0'; fprintf(Outfile, "%s\n", Row); } free(Row); return OK; }
int _TryPath(graphP theGraph, int e, int V) { int eTwin, nextVertex; nextVertex = gp_GetNeighbor(theGraph, e); // while nextVertex is strictly degree 2 while (gp_IsArc(gp_GetFirstArc(theGraph, nextVertex)) && gp_IsArc(gp_GetLastArc(theGraph, nextVertex)) && gp_GetNextArc(theGraph, gp_GetFirstArc(theGraph, nextVertex)) == gp_GetLastArc(theGraph, nextVertex)) { eTwin = gp_GetTwinArc(theGraph, e); e = gp_GetFirstArc(theGraph, nextVertex); if (e == eTwin) e = gp_GetLastArc(theGraph, nextVertex); nextVertex = gp_GetNeighbor(theGraph, e); } return nextVertex == V ? TRUE : FALSE; }
int _ComputeVertexRanges(DrawPlanarContext *context) { graphP theEmbedding = context->theGraph; int I, J, min, max; for (I = 0; I < theEmbedding->N; I++) { min = theEmbedding->M + 1; max = -1; // Iterate the edges, except in the isolated vertex case we just // set the min and max to 1 since there no edges controlling where // it gets drawn. J = gp_GetFirstArc(theEmbedding, I); if (!gp_IsArc(theEmbedding, J)) { min = max = 0; } else { while (gp_IsArc(theEmbedding, J)) { if (min > context->G[J].pos) min = context->G[J].pos; if (max < context->G[J].pos) max = context->G[J].pos; J = gp_GetNextArc(theEmbedding, J); } } context->G[I].start = min; context->G[I].end = max; } return OK; }
/******************************************************************** _CreateBackArcLists() ********************************************************************/ void _CreateBackArcLists(graphP theGraph, K33SearchContext *context) { int v, e, eTwin, ancestor; for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v); v++) { e = gp_GetVertexFwdArcList(theGraph, v); while (gp_IsArc(e)) { // Get the ancestor endpoint and the associated back arc ancestor = gp_GetNeighbor(theGraph, e); eTwin = gp_GetTwinArc(theGraph, e); // Put it into the back arc list of the ancestor if (gp_IsNotArc(context->VI[ancestor].backArcList)) { context->VI[ancestor].backArcList = eTwin; gp_SetPrevArc(theGraph, eTwin, eTwin); gp_SetNextArc(theGraph, eTwin, eTwin); } else { int eHead = context->VI[ancestor].backArcList; int eTail = gp_GetPrevArc(theGraph, eHead); gp_SetPrevArc(theGraph, eTwin, eTail); gp_SetNextArc(theGraph, eTwin, eHead); gp_SetPrevArc(theGraph, eHead, eTwin); gp_SetNextArc(theGraph, eTail, eTwin); } // Advance to the next forward edge e = gp_GetNextArc(theGraph, e); if (e == gp_GetVertexFwdArcList(theGraph, v)) e = NIL; } } }
int _DeleteUnmarkedVerticesAndEdges(graphP theGraph) { int I, J, fwdArc, descendant; /* All of the forward and back arcs of all of the edge records were removed from the adjacency lists in the planarity algorithm preprocessing. We now put them back into the adjacency lists (and we do not mark them), so they can be properly deleted below. */ for (I = 0; I < theGraph->N; I++) { while (theGraph->V[I].fwdArcList != NIL) { fwdArc = theGraph->V[I].fwdArcList; descendant = theGraph->G[fwdArc].v; _AddBackEdge(theGraph, I, descendant); } } /* Now we delete all unmarked edges. We don't delete vertices from the embedding, but the ones we should delete will become degree zero. */ for (I = 0; I < theGraph->N; I++) { J = gp_GetFirstArc(theGraph, I); while (gp_IsArc(theGraph, J)) { if (theGraph->G[J].visited) J = gp_GetNextArc(theGraph, J); else J = gp_DeleteEdge(theGraph, J, 0); } } return OK; }
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; }
int _WriteDebugInfo(graphP theGraph, FILE *Outfile) { int I, J, Gsize; if (theGraph==NULL || Outfile==NULL) return NOTOK; /* Print parent copy vertices and their adjacency lists */ fprintf(Outfile, "DEBUG N=%d M=%d\n", theGraph->N, theGraph->M); for (I=0; I < theGraph->N; I++) { fprintf(Outfile, "%d(P=%d,lA=%d,LowPt=%d,v=%d):", I, theGraph->V[I].DFSParent, theGraph->V[I].leastAncestor, theGraph->V[I].Lowpoint, theGraph->G[I].v); J = gp_GetFirstArc(theGraph, I); while (gp_IsArc(theGraph, J)) { fprintf(Outfile, " %d(J=%d)", theGraph->G[J].v, J); J = gp_GetNextArc(theGraph, J); } fprintf(Outfile, " %d\n", NIL); } /* Print any root copy vertices and their adjacency lists */ for (I = theGraph->N; I < 2*theGraph->N; I++) { if (theGraph->G[I].v == NIL) continue; fprintf(Outfile, "%d(copy of=%d, DFS child=%d):", I, theGraph->G[I].v, I-theGraph->N); J = gp_GetFirstArc(theGraph, I); while (gp_IsArc(theGraph, J)) { fprintf(Outfile, " %d(J=%d)", theGraph->G[J].v, J); J = gp_GetNextArc(theGraph, J); } fprintf(Outfile, " %d\n", NIL); } /* Print information about vertices and root copy (virtual) vertices */ fprintf(Outfile, "\nVERTEX INFORMATION\n"); for (I=0; I < 2*theGraph->N; I++) { if (theGraph->G[I].v == NIL) continue; fprintf(Outfile, "V[%3d] v=%3d, type=%c, first arc=%3d, last arc=%3d\n", I, theGraph->G[I].v, theGraph->G[I].type, gp_GetFirstArc(theGraph, I), gp_GetLastArc(theGraph, I)); } /* Print information about edges */ fprintf(Outfile, "\nEDGE INFORMATION\n"); Gsize = theGraph->edgeOffset + theGraph->arcCapacity; for (J=theGraph->edgeOffset; J < Gsize; J++) { if (theGraph->G[J].v == NIL) continue; fprintf(Outfile, "E[%3d] v=%3d, type=%c, next arc=%3d, prev arc=%3d\n", J, theGraph->G[J].v, theGraph->G[J].type, gp_GetNextArc(theGraph, J), gp_GetPrevArc(theGraph, J)); } return OK; }
int _ReadAdjList(graphP theGraph, FILE *Infile) { int N, I, W, ErrorCode, adjList, J; if (Infile == NULL) return NOTOK; fgetc(Infile); /* Skip the N= */ fgetc(Infile); fscanf(Infile, " %d ", &N); /* Read N */ if (gp_InitGraph(theGraph, N) != OK) { printf("Failed to init graph"); return NOTOK; } // Clear the visited members of the vertices so they can be used // during the adjacency list read operation for (I=0; I < N; I++) theGraph->G[I].visited = 0; // Do the adjacency list read operation for each vertex in order for (I = 0, ErrorCode = OK; I < N && ErrorCode==OK; I++) { // Read the vertex number fscanf(Infile, "%d", &theGraph->G[I].v); // The vertices are expected to be in numeric ascending order if (theGraph->G[I].v != I) return NOTOK; // Skip the colon after the vertex number fgetc(Infile); // If the vertex already has a non-empty adjacency list, then it is // the result of adding edges during processing of preceding vertices. // The list is removed from the current vertex I and saved for use // during the read operation for I. Adjacencies to preceding vertices // are pulled from this list, if present, or added as directed edges // if not. Adjacencies to succeeding vertices are added as undirected // edges, and will be corrected later if the succeeding vertex does not // have the matching adjacency using the following mechanism. After the // read operation for a vertex I, any adjacency nodes left in the saved // list are converted to directed edges from the preceding vertex to I. adjList = gp_GetFirstArc(theGraph, I); if (gp_IsArc(theGraph, adjList)) { // Store the adjacency node location in the visited member of each // of the preceding vertices to which I is adjacent so that we can // efficiently detect the adjacency during the read operation and // efficiently find the adjacency node. J = gp_GetFirstArc(theGraph, I); while (gp_IsArc(theGraph, J)) { theGraph->G[theGraph->G[J].v].visited = J; J = gp_GetNextArc(theGraph, J); } // Make the adjacency list circular, for later ease of processing gp_SetPrevArc(theGraph, adjList, gp_GetLastArc(theGraph, I)); gp_SetNextArc(theGraph, gp_GetLastArc(theGraph, I), adjList); // Remove the list from the vertex gp_SetFirstArc(theGraph, I, gp_AdjacencyListEndMark(I)); gp_SetLastArc(theGraph, I, gp_AdjacencyListEndMark(I)); } // Read the adjacency list. while (1) { // Read the next adjacent vertex, with NIL indicating the list end fscanf(Infile, " %d ", &W); if (W < 0) break; // Vertex numbers must be less than N if (W >= N) ErrorCode = NOTOK; // Loop edges are not supported, but no reason to throw an error if they occur // If a loop occurs, we just do like the ostrich and ignore it else if (W == I) ErrorCode = OK; // If the adjacency is to a succeeding, higher numbered vertex, // then we'll add an undirected edge for now else if (I < W) { ErrorCode = gp_AddEdge(theGraph, I, 0, W, 0); } // If the adjacency is to a preceding, lower numbered vertex, then // we have to pull the adjacency node from the preexisting adjList, // if it is there, and if not then we have to add a directed edge. else { // If the adjacency node (arc) already exists, then we add it // as the new first arc of the vertex and delete it from adjList if (theGraph->G[W].visited) { J = theGraph->G[W].visited; // Remove the arc J from the adjList construct theGraph->G[W].visited = 0; if (adjList == J) { if ((adjList = gp_GetNextArc(theGraph, J)) == J) adjList = NIL; } gp_SetPrevArc(theGraph, gp_GetNextArc(theGraph, J), gp_GetPrevArc(theGraph, J)); gp_SetNextArc(theGraph, gp_GetPrevArc(theGraph, J), gp_GetNextArc(theGraph, J)); gp_AttachFirstArc(theGraph, I, J); } // If an adjacency node to the lower numbered vertex W does not // already exist, then we make a new directed arc from the current // vertex I to W. else { // It is added as the new first arc in both vertices ErrorCode = gp_AddEdge(theGraph, I, 0, W, 0); if (ErrorCode == OK) // Note that this call also sets OUTONLY on the twin arc gp_SetDirection(theGraph, gp_GetFirstArc(theGraph, W), EDGEFLAG_DIRECTION_INONLY); } } if (ErrorCode != OK) break; } // If there are still adjList entries after the read operation // then those entries are not representative of full undirected edges. // Rather, they represent incoming directed arcs from other vertices // into vertex I. They need to be added back into I's adjacency list but // marked as "INONLY", while the twin is marked "OUTONLY" (by the same function). while (gp_IsArc(theGraph, adjList)) { J = adjList; theGraph->G[theGraph->G[J].v].visited = 0; if ((adjList = gp_GetNextArc(theGraph, J)) == J) adjList = NIL; gp_SetPrevArc(theGraph, gp_GetNextArc(theGraph, J), gp_GetPrevArc(theGraph, J)); gp_SetNextArc(theGraph, gp_GetPrevArc(theGraph, J), gp_GetNextArc(theGraph, J)); gp_AttachFirstArc(theGraph, I, J); gp_SetDirection(theGraph, J, EDGEFLAG_DIRECTION_INONLY); } } return ErrorCode; }
int _TestSubgraph(graphP theSubgraph, graphP theGraph) { int v, e, degreeCount; int Result = TRUE; int invokeSortOnGraph = FALSE; int invokeSortOnSubgraph = FALSE; // If the graph is not sorted by DFI, but the alleged subgraph is, // then "unsort" the alleged subgraph so both have the same vertex order if (!(theGraph->internalFlags & FLAGS_SORTEDBYDFI) && (theSubgraph->internalFlags & FLAGS_SORTEDBYDFI)) { invokeSortOnSubgraph = TRUE; gp_SortVertices(theSubgraph); } // If the graph is not sorted by DFI, but the alleged subgraph is, // then "unsort" the alleged subgraph so both have the same vertex order if (!(theSubgraph->internalFlags & FLAGS_SORTEDBYDFI) && (theGraph->internalFlags & FLAGS_SORTEDBYDFI)) { invokeSortOnGraph = TRUE; gp_SortVertices(theGraph); } /* We clear all visitation flags */ _ClearVertexVisitedFlags(theGraph, FALSE); /* For each vertex... */ for (v = gp_GetFirstVertex(theSubgraph), degreeCount = 0; gp_VertexInRange(theSubgraph, v); v++) { /* For each neighbor w in the adjacency list of vertex v in the subgraph, set the visited flag in w in the graph */ e = gp_GetFirstArc(theSubgraph, v); while (gp_IsArc(e)) { if (gp_IsNotVertex(gp_GetNeighbor(theSubgraph, e))) { Result = FALSE; break; } degreeCount++; gp_SetVertexVisited(theGraph, gp_GetNeighbor(theSubgraph, e)); e = gp_GetNextArc(theSubgraph, e); } if (Result != TRUE) break; /* For each neighbor w in the adjacency list of vertex v in the graph, clear the visited flag in w in the graph */ e = gp_GetFirstArc(theGraph, v); while (gp_IsArc(e)) { if (gp_IsNotVertex(gp_GetNeighbor(theGraph, e))) { Result = FALSE; break; } gp_ClearVertexVisited(theGraph, gp_GetNeighbor(theGraph, e)); e = gp_GetNextArc(theGraph, e); } if (Result != TRUE) break; /* For each neighbor w in the adjacency list of vertex v in the subgraph, ensure that the visited flag in w was cleared (otherwise, the "subgraph" would incorrectly contain an adjacency not contained in the ("super") graph) */ e = gp_GetFirstArc(theSubgraph, v); while (gp_IsArc(e)) { if (gp_GetVertexVisited(theGraph, gp_GetNeighbor(theSubgraph, e))) { Result = FALSE; break; } e = gp_GetNextArc(theSubgraph, e); } if (Result != TRUE) break; } // Restore the DFI sort order of either graph if it had to be reordered at the start if (invokeSortOnSubgraph) gp_SortVertices(theSubgraph); if (invokeSortOnGraph) gp_SortVertices(theGraph); // Assuming theSubgraph is a subgraph, we also do an extra integrity check to ensure // proper edge array utilization if (Result == TRUE) { // If the edge count is wrong, we fail the subgraph test in a way that invokes // the name NOTOK so that in debug mode there is more trace on the failure. if (degreeCount != 2*theSubgraph->M) Result = NOTOK == FALSE ? NOTOK : FALSE; } return Result; }
int _TestForK23GraphObstruction(graphP theGraph, int *degrees, int *imageVerts) { int v, e, imageVertPos; // This function operates over the imageVerts results produced by // getImageVertices, which only finds vertices of degree 3 or higher. // So, for a K2,3, there must be exactly two degree 3 vertices and // no degree 4 vertices. if (degrees[3] != 2) return FALSE; // For K_{2,3}, the three vertices of degree 2 were not // detected as image vertices because degree 2 vertices // are indistinguishable from the internal path vertices // between the image vertices. So, here we acknowledge // that more image vertices need to be selected. imageVertPos = 2; // Assign the remaining three image vertices to be the // neighbors of the first degree 3 image vertex. // Ensure that each is distinct from the second // degree 3 image vertex. This must be the case because // the two degree 3 image vertices are in the same partition // and hence must not be adjacent. e = gp_GetFirstArc(theGraph, imageVerts[0]); while (gp_IsArc(e)) { imageVerts[imageVertPos] = gp_GetNeighbor(theGraph, e); if (imageVerts[imageVertPos] == imageVerts[1]) return FALSE; imageVertPos++; e = gp_GetNextArc(theGraph, e); } /* The paths from imageVerts[0] to each of the new degree 2 image vertices are the edges we just traversed. Now test the paths between each of the degree 2 image vertices and imageVerts[1]. */ _ClearVertexVisitedFlags(theGraph, FALSE); for (imageVertPos=2; imageVertPos<5; imageVertPos++) { if (_TestPath(theGraph, imageVerts[imageVertPos], imageVerts[1]) != TRUE) return FALSE; gp_SetVertexVisited(theGraph, imageVerts[imageVertPos]); } for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v); v++) if (gp_GetVertexVisited(theGraph, v)) degrees[2]--; /* If every degree 2 vertex is used in a path between the two degree 3 image vertices, then there are no extra pieces of the graph in theGraph. Specifically, the prior tests identify a K_{2,3} and ensure that nothing else could exist in the graph... except extra degree 2 vertices joined in a cycle. We return NOTOK in that case. */ return degrees[2] == 0 ? TRUE : FALSE; }
int _ComputeEdgePositions(DrawPlanarContext *context) { graphP theEmbedding = context->theGraph; int *vertexOrder = NULL; listCollectionP edgeList = NULL; int edgeListHead, edgeListInsertPoint; int I, J, Jcur, e, v, vpos; int eIndex, JTwin; gp_LogLine("\ngraphDrawPlanar.c/_ComputeEdgePositions() start"); // Sort the vertices by vertical position (in linear time) if ((vertexOrder = (int *) malloc(theEmbedding->N * sizeof(int))) == NULL) return NOTOK; for (I = 0; I < theEmbedding->N; I++) vertexOrder[context->G[I].pos] = I; // Allocate the edge list of size M. // This is an array of (prev, next) pointers. // An edge at position X corresponds to the edge // at position X in the graph structure, which is // represented by a pair of adjacent graph nodes // starting at index 2N + 2X. if (theEmbedding->M > 0 && (edgeList = LCNew(theEmbedding->M)) == NULL) { free(vertexOrder); return NOTOK; } edgeListHead = NIL; // Each vertex starts out with a NIL generator edge. for (I=0; I < theEmbedding->N; I++) theEmbedding->G[I].visited = NIL; // Perform the vertical sweep of the combinatorial embedding, using // the vertex ordering to guide the sweep. // For each vertex, each edge leading to a vertex with a higher number in // the vertex order is recorded as the "generator edge", or the edge of // first discovery of that higher numbered vertex, unless the vertex already has // a recorded generator edge for (vpos=0; vpos < theEmbedding->N; vpos++) { // Get the vertex associated with the position v = vertexOrder[vpos]; gp_LogLine(gp_MakeLogStr3("Processing vertex %d with DFI=%d at position=%d", theEmbedding->G[v].v, v, vpos)); // The DFS tree root of a connected component is always the least // number vertex in the vertex ordering. We have to give it a // false generator edge so that it is still "visited" and then // all of its edges are generators for its neighbor vertices because // they all have greater numbers in the vertex order. if (theEmbedding->V[v].DFSParent == NIL) { // False generator edge, so the vertex is distinguishable from // a vertex with no generator edge when its neighbors are visited // This way, an edge from a neighbor won't get recorded as the // generator edge of the DFS tree root. theEmbedding->G[v].visited = 1; // Now we traverse the adjacency list of the DFS tree root and // record each edge as the generator edge of the neighbors J = gp_GetFirstArc(theEmbedding, v); while (gp_IsArc(theGraph, J)) { e = (J - theEmbedding->edgeOffset) / 2; edgeListHead = LCAppend(edgeList, edgeListHead, e); gp_LogLine(gp_MakeLogStr2("Append generator edge (%d, %d) to edgeList", theEmbedding->G[v].v, theEmbedding->G[theEmbedding->G[J].v].v)); // Set the generator edge for the root's neighbor theEmbedding->G[theEmbedding->G[J].v].visited = J; // Go to the next node of the root's adj list J = gp_GetNextArc(theEmbedding, J); } } // Else, if we are not on a DFS tree root... else { // Get the generator edge of the vertex if ((JTwin = theEmbedding->G[v].visited) == NIL) return NOTOK; J = gp_GetTwinArc(theEmbedding, JTwin); // Traverse the edges of the vertex, starting // from the generator edge and going counterclockwise... e = (J - theEmbedding->edgeOffset) / 2; edgeListInsertPoint = e; Jcur = gp_GetNextArcCircular(theEmbedding, J); while (Jcur != J) { // If the neighboring vertex's position is greater // than the current vertex (meaning it is lower in the // diagram), then add that edge to the edge order. if (context->G[theEmbedding->G[Jcur].v].pos > vpos) { e = (Jcur - theEmbedding->edgeOffset) / 2; LCInsertAfter(edgeList, edgeListInsertPoint, e); gp_LogLine(gp_MakeLogStr4("Insert (%d, %d) after (%d, %d)", theEmbedding->G[v].v, theEmbedding->G[theEmbedding->G[Jcur].v].v, theEmbedding->G[theEmbedding->G[gp_GetTwinArc(theEmbedding, J)].v].v, theEmbedding->G[theEmbedding->G[J].v].v)); edgeListInsertPoint = e; // If the vertex does not yet have a generator edge, then set it. if (theEmbedding->G[theEmbedding->G[Jcur].v].visited == NIL) { theEmbedding->G[theEmbedding->G[Jcur].v].visited = Jcur; gp_LogLine(gp_MakeLogStr2("Generator edge (%d, %d)", theEmbedding->G[theEmbedding->G[gp_GetTwinArc(theEmbedding, J)].v].v, theEmbedding->G[theEmbedding->G[Jcur].v].v)); } } // Go to the next node in v's adjacency list Jcur = gp_GetNextArcCircular(theEmbedding, Jcur); } } #ifdef LOGGING _LogEdgeList(theEmbedding, edgeList, edgeListHead); #endif } // Now iterate through the edgeList and assign positions to the edges. eIndex = 0; e = edgeListHead; while (e != NIL) { J = theEmbedding->edgeOffset + 2*e; JTwin = gp_GetTwinArc(theEmbedding, J); context->G[J].pos = context->G[JTwin].pos = eIndex; eIndex++; e = LCGetNext(edgeList, edgeListHead, e); } // Clean up and return LCFree(&edgeList); free(vertexOrder); gp_LogLine("graphDrawPlanar.c/_ComputeEdgePositions() end\n"); return OK; }
int _ComputeVertexPositionsInComponent(DrawPlanarContext *context, int root, int *pIndex) { graphP theEmbedding = context->theGraph; listCollectionP theOrder = LCNew(theEmbedding->N); int W, P, C, V, J; if (theOrder == NULL) return NOTOK; // Determine the vertex order using a depth first search with // pre-order visitation. sp_ClearStack(theEmbedding->theStack); sp_Push(theEmbedding->theStack, root); while (!sp_IsEmpty(theEmbedding->theStack)) { sp_Pop(theEmbedding->theStack, W); P = theEmbedding->V[W].DFSParent; V = context->V[W].ancestor; C = context->V[W].ancestorChild; // For the special case that we just popped the DFS tree root, // we simply add the root to its own position. if (P == NIL) { // Put the DFS root in the list by itself LCAppend(theOrder, NIL, W); // The children of the DFS root have the root as their // ancestorChild and 'beyond' as the drawingFlag, so this // causes the root's children to be placed below the root context->V[W].drawingFlag = DRAWINGFLAG_BELOW; } // Determine vertex W position relative to P else { // An unresolved tie is an error if (context->V[W].drawingFlag == DRAWINGFLAG_TIE) return NOTOK; // If C below V, then P below V, so interpret W between // P and V as W above P, and interpret W beyond P relative // to V as W below P. if (context->V[C].drawingFlag == DRAWINGFLAG_BELOW) { if (context->V[W].drawingFlag == DRAWINGFLAG_BETWEEN) context->V[W].drawingFlag = DRAWINGFLAG_ABOVE; else context->V[W].drawingFlag = DRAWINGFLAG_BELOW; } // If C above V, then P above V, so interpret W between // P and V as W below P, and interpret W beyond P relative // to V as W above P. else { if (context->V[W].drawingFlag == DRAWINGFLAG_BETWEEN) context->V[W].drawingFlag = DRAWINGFLAG_BELOW; else context->V[W].drawingFlag = DRAWINGFLAG_ABOVE; } if (context->V[W].drawingFlag == DRAWINGFLAG_BELOW) LCInsertAfter(theOrder, P, W); else LCInsertBefore(theOrder, P, W); } // Push DFS children J = gp_GetFirstArc(theEmbedding, W); while (gp_IsArc(theEmbedding, J)) { if (theEmbedding->G[J].type == EDGE_DFSCHILD) sp_Push(theEmbedding->theStack, theEmbedding->G[J].v); J = gp_GetNextArc(theEmbedding, J); } } // Use the order to assign vertical positions V = root; while (V != NIL) { context->G[V].pos = *pIndex; (*pIndex)++; V = LCGetNext(theOrder, root, V); } // Clean up and return LCFree(&theOrder); return OK; }
int gp_LowpointAndLeastAncestor(graphP theGraph) { stackP theStack = theGraph->theStack; int I, u, uneighbor, J, L, leastAncestor; int totalVisited = 0; #ifdef PROFILE platform_time start, end; platform_GetTime(start); #endif sp_ClearStack(theStack); for (I=0; I < theGraph->N; I++) theGraph->G[I].visited = 0; /* This outer loop causes the connected subgraphs of a disconnected graph to be processed */ for (I=0; I < theGraph->N && totalVisited < theGraph->N; I++) { if (theGraph->G[I].visited) continue; sp_Push(theStack, I); while (sp_NonEmpty(theStack)) { sp_Pop(theStack, u); if (!theGraph->G[u].visited) { /* Mark u as visited, then push it back on the stack */ theGraph->G[u].visited = 1; totalVisited++; sp_Push(theStack, u); /* Push DFS children */ J = gp_GetFirstArc(theGraph, u); while (gp_IsArc(theGraph, J)) { if (theGraph->G[J].type == EDGE_DFSCHILD) { sp_Push(theStack, theGraph->G[J].v); } else break; J = gp_GetNextArc(theGraph, J); } } else { /* Start with high values because we are doing a min function */ L = leastAncestor = u; /* Compute L and leastAncestor */ J = gp_GetFirstArc(theGraph, u); while (gp_IsArc(theGraph, J)) { uneighbor = theGraph->G[J].v; if (theGraph->G[J].type == EDGE_DFSCHILD) { if (L > theGraph->V[uneighbor].Lowpoint) L = theGraph->V[uneighbor].Lowpoint; } else if (theGraph->G[J].type == EDGE_BACK) { if (leastAncestor > uneighbor) leastAncestor = uneighbor; } else if (theGraph->G[J].type == EDGE_FORWARD) break; J = gp_GetNextArc(theGraph, J); } /* Assign leastAncestor and Lowpoint to the vertex */ theGraph->V[u].leastAncestor = leastAncestor; theGraph->V[u].Lowpoint = leastAncestor < L ? leastAncestor : L; } } } #ifdef PROFILE platform_GetTime(end); printf("Lowpoint in %.3lf seconds.\n", platform_GetDuration(start,end)); #endif return OK; }