int _AddAndMarkEdge(graphP theGraph, int ancestor, int descendant) { _AddBackEdge(theGraph, ancestor, descendant); /* Mark the edge so it is not deleted */ gp_SetVertexVisited(theGraph, ancestor); gp_SetEdgeVisited(theGraph, gp_GetFirstArc(theGraph, ancestor)); gp_SetEdgeVisited(theGraph, gp_GetFirstArc(theGraph, descendant)); gp_SetVertexVisited(theGraph, descendant); return OK; }
int _AddAndMarkEdge(graphP theGraph, int ancestor, int descendant) { _AddBackEdge(theGraph, ancestor, descendant); /* Mark the edge so it is not deleted */ theGraph->G[ancestor].visited = 1; theGraph->G[gp_GetFirstArc(theGraph, ancestor)].visited = 1; theGraph->G[gp_GetFirstArc(theGraph, descendant)].visited = 1; theGraph->G[descendant].visited = 1; 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; }
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 _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; }
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; }
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); }
/**************************************************************************** _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; }
void _MarkExternalFaceVertices(graphP theGraph, int startVertex) { int nextVertex = startVertex; int e = gp_GetFirstArc(theGraph, nextVertex); int eTwin; // Handle the case of an isolated vertex if (gp_IsNotArc(e)) { gp_SetVertexVisited(theGraph, startVertex); return; } // Process a non-trivial connected component do { gp_SetVertexVisited(theGraph, nextVertex); // The arc out of the vertex just visited points to the next vertex nextVertex = gp_GetNeighbor(theGraph, e); // Arc used to enter the next vertex is needed so we can get the // next edge in rotation order. // Note: for bicomps, first and last arcs of all external face vertices // indicate the edges that hold them to the external face // But _JoinBicomps() has already occurred, so cut vertices // will have external face edges other than the first and last arcs // Hence we need this more sophisticated traversal method eTwin = gp_GetTwinArc(theGraph, e); // Now we get the next arc in rotation order as the new arc out to the // vertex after nextVertex. This sets us up for the next iteration. // Note: We cannot simply follow the chain of nextVertex first arcs // as we started out doing at the top of this method. This is // because we are no longer dealing with bicomps only. // Since _JoinBicomps() has already been invoked, there may now // be cut vertices on the external face whose adjacency lists // contain external face arcs in positions other than the first and // and last arcs. We will visit those vertices multiple times, // which is OK (just that we have to explain why we're calculating // jout in this way). e = gp_GetNextArcCircular(theGraph, eTwin); // Now things get really interesting. The DFS root (startVertex) may // itself be a cut vertex to which multiple bicomps have been joined. // So we cannot simply stop when the external face walk gets back to // startVertex. We must actually get back to startVertex using its // last arc. This ensures that we've looped down into all the DFS // subtrees rooted at startVertex and walked their external faces. // Since we started the whole external face walk with the first arc // of startVertex, we need to proceed until we reenter startVertex // using its last arc. } while (eTwin != gp_GetLastArc(theGraph, startVertex)); }
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; }
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 _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 _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 _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 _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; }
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 _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 _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 _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 _MarkZtoRPath(graphP theGraph) { int ZPrevArc, ZNextArc, Z, R, Px, Py; /* Initialize */ R = theGraph->IC.r; Px = theGraph->IC.px; Py = theGraph->IC.py; theGraph->IC.z = NIL; /* Begin at Px and search its adjacency list for the edge leading to the first internal vertex of the X-Y path. */ Z = Px; ZNextArc = gp_GetLastArc(theGraph, Z); while (ZNextArc != gp_GetFirstArc(theGraph, Z)) { if (theGraph->G[ZNextArc].visited) break; ZNextArc = gp_GetPrevArc(theGraph, ZNextArc); } if (!theGraph->G[ZNextArc].visited) return NOTOK; /* For each internal vertex Z, determine whether it has a path to root. */ while (theGraph->G[ZNextArc].visited) { ZPrevArc = gp_GetTwinArc(theGraph, ZNextArc); ZNextArc = gp_GetPrevArcCircular(theGraph, ZPrevArc); } ZPrevArc = gp_GetTwinArc(theGraph, ZNextArc); Z = theGraph->G[ZPrevArc].v; /* If there is no Z to R path, return */ if (Z == Py) return OK; /* Otherwise, store Z in the isolation context */ theGraph->IC.z = Z; /* Walk the proper face starting with (Z, ZNextArc) until we reach R, marking the vertices and edges encountered along the way, then Return OK. */ while (Z != R) { /* If we ever encounter a non-internal vertex (other than the root R), then corruption has occured, so we return NOTOK */ if (theGraph->G[Z].type != TYPE_UNKNOWN) return NOTOK; /* Go to the next vertex indicated by ZNextArc */ Z = theGraph->G[ZNextArc].v; /* Mark the next vertex and the edge leading to it as visited. */ theGraph->G[ZNextArc].visited = 1; theGraph->G[ZPrevArc].visited = 1; theGraph->G[Z].visited = 1; /* Go to the next edge in the proper face */ ZNextArc = gp_GetPrevArcCircular(theGraph, ZPrevArc); ZPrevArc = gp_GetTwinArc(theGraph, ZNextArc); } /* Found Z to R path, so indicate as much to caller */ return OK; }
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_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 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; }
int _K33Search_MarkDFSPath(graphP theGraph, int ancestor, int descendant) { int J, parent, 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 (the one 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) { if (descendant == NIL) return NOTOK; /* If we are at a bicomp root, then ascend to its parent copy and mark it as visited. */ if (descendant >= N) { parent = theGraph->V[descendant-N].DFSParent; } /* 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; J = gp_GetFirstArc(theGraph, descendant); while (gp_IsArc(theGraph, J)) { if (theGraph->G[J].type == EDGE_DFSPARENT) { parent = theGraph->G[J].v; break; } J = gp_GetNextArc(theGraph, J); } /* If the desired edge was not found, then the data structure is corrupt, so bail out. */ if (parent == NIL) return NOTOK; /* Mark the edge */ theGraph->G[J].visited = 1; theGraph->G[gp_GetTwinArc(theGraph, J)].visited = 1; } /* Mark the parent, then hop to the parent and reiterate */ theGraph->G[parent].visited = 1; descendant = parent; } return OK; }