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)); }
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 _WriteAdjList(graphP theGraph, FILE *Outfile) { int I, J; if (theGraph==NULL || Outfile==NULL) return NOTOK; fprintf(Outfile, "N=%d\n", theGraph->N); for (I=0; I < theGraph->N; I++) { fprintf(Outfile, "%d:", I); J = gp_GetLastArc(theGraph, I); while (gp_IsArc(theGraph, J)) { if (!gp_GetDirection(theGraph, J, EDGEFLAG_DIRECTION_INONLY)) fprintf(Outfile, " %d", theGraph->G[J].v); J = gp_GetPrevArc(theGraph, J); } fprintf(Outfile, " %d\n", NIL); } 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 _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 _MarkHighestXYPath(graphP theGraph) { int J, Z; int R, X, Y, W; int stackBottom1, stackBottom2; /* Initialization */ R = theGraph->IC.r; X = theGraph->IC.x; Y = theGraph->IC.y; W = theGraph->IC.w; theGraph->IC.px = theGraph->IC.py = NIL; /* Save the stack bottom before we start hiding internal edges, so we will know how many edges to restore */ stackBottom1 = sp_GetCurrentSize(theGraph->theStack); /* Remove the internal edges incident to vertex R */ if (_HideInternalEdges(theGraph, R) != OK) return NOTOK; /* Now we're going to use the stack to collect the vertices of potential * X-Y paths, so we need to store where the hidden internal edges are * located because we must, at times, pop the collected vertices if * the path being collected doesn't work out. */ stackBottom2 = sp_GetCurrentSize(theGraph->theStack); /* Walk the proper face containing R to find and mark the highest X-Y path. Note that if W is encountered, then there is no intervening X-Y path, so we would return FALSE in that case. */ Z = R; // This setting of J is the arc equivalent of prevLink=1 // As loop progresses, J indicates the arc used to enter Z, not the exit arc J = gp_GetLastArc(theGraph, R); while (theGraph->G[Z].type != VERTEX_HIGH_RYW && theGraph->G[Z].type != VERTEX_LOW_RYW) { /* Advance J and Z along the proper face containing R */ J = gp_GetPrevArcCircular(theGraph, J); Z = theGraph->G[J].v; J = gp_GetTwinArc(theGraph, J); /* If Z is already visited, then pop everything since the last time we visited Z because its all part of a separable component. */ if (theGraph->G[Z].visited) { if (_PopAndUnmarkVerticesAndEdges(theGraph, Z, stackBottom2) != OK) return NOTOK; } /* If we have not visited this vertex before... */ else { /* If we find W, then there is no X-Y path. Never happens for Kuratowski subgraph isolator, but this routine is also used to test for certain X-Y paths. So, we clean up and bail out in that case. */ if (Z == W) { if (_PopAndUnmarkVerticesAndEdges(theGraph, NIL, stackBottom2) != OK) return NOTOK; break; } /* If we found another vertex along the RXW path, then blow off all the vertices we visited so far because they're not part of the obstructing path */ if (theGraph->G[Z].type == VERTEX_HIGH_RXW || theGraph->G[Z].type == VERTEX_LOW_RXW) { theGraph->IC.px = Z; if (_PopAndUnmarkVerticesAndEdges(theGraph, NIL, stackBottom2) != OK) return NOTOK; } /* Push the current vertex onto the stack of vertices visited since the last RXW vertex was encountered */ sp_Push(theGraph->theStack, J); sp_Push(theGraph->theStack, Z); /* Mark the vertex Z as visited as well as its edge of entry (except the entry edge for P_x).*/ theGraph->G[Z].visited = 1; if (Z != theGraph->IC.px) { theGraph->G[J].visited = 1; theGraph->G[gp_GetTwinArc(theGraph, J)].visited = 1; } /* If we found an RYW vertex, then we have successfully finished identifying the highest X-Y path, so we record the point of attachment and break the loop. */ if (theGraph->G[Z].type == VERTEX_HIGH_RYW || theGraph->G[Z].type == VERTEX_LOW_RYW) { theGraph->IC.py = Z; break; } } } /* Remove any remaining vertex-edge pairs on the top of the stack, then Restore the internal edges incident to R that were previously removed. */ sp_SetCurrentSize(theGraph->theStack, stackBottom2); if (_RestoreInternalEdges(theGraph, stackBottom1) != OK) return NOTOK; /* Return the result */ return theGraph->IC.py==NIL ? FALSE : TRUE; }
int _K33Search_CreateFwdArcLists(graphP theGraph) { K33SearchContext *context = NULL; gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context); if (context == NULL) return NOTOK; // For isolating a K_{3,3} homeomorph, we need the forward edges // of each vertex to be in sorted order by DFI of descendants. // Otherwise we just drop through to the normal processing... if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK33) { int I, Jcur, Jnext, ancestor; // for each vertex v in order, we follow each of its back edges // to the twin forward edge in an ancestor u, then we move // the forward edge to the fwdArcList of u. Since this loop // processes vertices in order, the fwdArcList of each vertex // will be in order by the neighbor indicated by the forward edges. for (I=0; I < theGraph->N; I++) { // Skip this vertex if it has no edges Jnext = gp_GetLastArc(theGraph, I); if (!gp_IsArc(theGraph, Jnext)) continue; // Skip the forward edges, which are in succession at the // end of the arc list (last and its predecessors) while (theGraph->G[Jnext].type == EDGE_FORWARD) Jnext = gp_GetPrevArc(theGraph, Jnext); // Now we want to put all the back arcs in a backArcList, too. // Since we've already skipped past the forward arcs, we continue // with the predecessor arcs until we either run out of arcs or // we find a DFS child arc (the DFS child arcs are in succession // at the beginning of the arc list, so when a child arc is // encountered in the predecessor direction, then there won't be // any more back arcs. while (gp_IsArc(theGraph, Jnext) && theGraph->G[Jnext].type != EDGE_DFSCHILD) { Jcur = Jnext; Jnext = gp_GetPrevArc(theGraph, Jnext); if (theGraph->G[Jcur].type == EDGE_BACK) { // Remove the back arc from I's adjacency list gp_DetachArc(theGraph, Jcur); // Put the back arc in the backArcList if (context->V[I].backArcList == NIL) { context->V[I].backArcList = Jcur; gp_SetPrevArc(theGraph, Jcur, Jcur); gp_SetNextArc(theGraph, Jcur, Jcur); } else { gp_AttachArc(theGraph, NIL, context->V[I].backArcList, 1, Jcur); } // Determine the ancestor of vertex I to which Jcur connects ancestor = theGraph->G[Jcur].v; // Go to the forward arc in the ancestor Jcur = gp_GetTwinArc(theGraph, Jcur); // Remove the forward arc from the ancestor's adjacency list gp_DetachArc(theGraph, Jcur); // Add the forward arc to the end of the fwdArcList. if (theGraph->V[ancestor].fwdArcList == NIL) { theGraph->V[ancestor].fwdArcList = Jcur; gp_SetPrevArc(theGraph, Jcur, Jcur); gp_SetNextArc(theGraph, Jcur, Jcur); } else { gp_AttachArc(theGraph, NIL, theGraph->V[ancestor].fwdArcList, 1, Jcur); } } } } // Since the fwdArcLists have been created, we do not fall through // to run the superclass implementation return OK; } // If we're not actually running a K3,3 search, then we just run the // superclass implementation return context->functions.fpCreateFwdArcLists(theGraph); }