int _CheckAllVerticesOnExternalFace(graphP theGraph) { int v; // Mark all vertices unvisited _ClearVertexVisitedFlags(theGraph, FALSE); // For each connected component, walk its external face and // mark the vertices as visited for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v); v++) { if (gp_IsDFSTreeRoot(theGraph, v)) _MarkExternalFaceVertices(theGraph, v); } // If any vertex is unvisited, then the embedding is not an outerplanar // embedding, so we return NOTOK for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v); v++) if (!gp_GetVertexVisited(theGraph, v)) return NOTOK; // All vertices were found on external faces of the connected components // so the embedding is an outerplanar embedding and we return OK 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 SaveAsciiGraph(graphP theGraph, char *filename) { int e, EsizeOccupied, vertexLabelFix; FILE *outfile = fopen(filename, "wt"); fprintf(outfile, "%s\n", filename); // This edge list file format uses 1-based vertex numbering, and the current code // internally uses 1-based indexing by default, so this vertex label 'fix' adds zero // But earlier code used 0-based indexing and added one on output, so we replicate // that behavior in case the current code has been compiled with zero-based indexing. vertexLabelFix = 1 - gp_GetFirstVertex(theGraph); // Iterate over the edges of the graph EsizeOccupied = gp_EdgeInUseIndexBound(theGraph); for (e = gp_GetFirstEdge(theGraph); e < EsizeOccupied; e+=2) { // Only output edges that haven't been deleted (i.e. skip the edge holes) if (gp_EdgeInUse(theGraph, e)) { fprintf(outfile, "%d %d\n", gp_GetNeighbor(theGraph, e) + vertexLabelFix, gp_GetNeighbor(theGraph, e+1) + vertexLabelFix); } } // Since vertex numbers are at least 1, this indicates the end of the edge list fprintf(outfile, "0 0\n"); fclose(outfile); }
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 _getImageVertices(graphP theGraph, int *degrees, int maxDegree, int *imageVerts, int maxNumImageVerts) { int K, v, imageVertPos, degree; for (degree = 0; degree <= maxDegree; degree++) degrees[degree] = 0; for (K = 0; K < maxNumImageVerts; K++) imageVerts[K] = NIL; imageVertPos = 0; for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v); v++) { degree = gp_GetVertexDegree(theGraph, v); if (degree == 1) return NOTOK; if (degree > maxDegree) return NOTOK; degrees[degree]++; if (imageVertPos < maxNumImageVerts && degree > 2) imageVerts[imageVertPos++] = v; else if (degree > 2) return NOTOK; } return OK; }
void _CreateSeparatedDFSChildLists(graphP theGraph, K33SearchContext *context) { int *buckets; listCollectionP bin; int v, L, DFSParent, theList; buckets = context->buckets; bin = context->bin; // Initialize the bin and all the buckets to be empty LCReset(bin); for (L = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, L); L++) buckets[L] = NIL; // For each vertex, add it to the bucket whose index is equal to the lowpoint of the vertex. for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v); v++) { L = gp_GetVertexLowpoint(theGraph, v); buckets[L] = LCAppend(bin, buckets[L], v); } // For each bucket, add each vertex in the bucket to the separatedDFSChildList of its DFSParent. // Since lower numbered buckets are processed before higher numbered buckets, vertices with lower // lowpoint values are added before those with higher lowpoint values, so the separatedDFSChildList // of each vertex is sorted by lowpoint for (L = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, L); L++) { v = buckets[L]; // Loop through all the vertices with lowpoint L, putting each in the list of its parent while (gp_IsVertex(v)) { DFSParent = gp_GetVertexParent(theGraph, v); if (gp_IsVertex(DFSParent) && DFSParent != v) { theList = context->VI[DFSParent].separatedDFSChildList; theList = LCAppend(context->separatedDFSChildLists, theList, v); context->VI[DFSParent].separatedDFSChildList = theList; } v = LCGetNext(bin, buckets[L], v); } } }
int _TestForK33GraphObstruction(graphP theGraph, int *degrees, int *imageVerts) { int v, K, imageVertPos, temp, success; if (degrees[4] != 0) return FALSE; if (degrees[3] != 6) return FALSE; /* Partition the six image vertices into two sets of 3 (or report failure) */ for (imageVertPos = 3; imageVertPos < 6; imageVertPos++) { K = 0; success = FALSE; do { if (_TestPath(theGraph, imageVerts[imageVertPos], imageVerts[0]) == TRUE) { success = TRUE; break; } K++; temp = imageVerts[K]; imageVerts[K] = imageVerts[imageVertPos]; imageVerts[imageVertPos] = temp; } while (K < 3); if (!success) return FALSE; } /* Now test the paths between each of the first three vertices and each of the last three vertices */ _ClearVertexVisitedFlags(theGraph, FALSE); for (imageVertPos=0; imageVertPos<3; imageVertPos++) for (K=3; K<6; K++) if (_TestPath(theGraph, imageVerts[imageVertPos], imageVerts[K]) != TRUE) return FALSE; 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 image vertices, then there are no extra pieces of the graph in theGraph. Specifically, the prior tests identify a K_{3,3} and ensure that nothing else could exist in the graph except extra degree 2 vertices, which must be joined in a cycle so that all are degree 2. */ return degrees[2] == 0 ? TRUE : FALSE; }
int _TestForCompleteGraphObstruction(graphP theGraph, int numVerts, int *degrees, int *imageVerts) { int v, w; // We need to make sure we have numVerts vertices of degree numVerts-1 // For example, if numVerts==5, then we're looking for a K5, so we // need to have degrees[4] == 5 (5 vertices of degree 4) if (degrees[numVerts-1] != numVerts) return FALSE; // All vertices need to be degree 0, degree 2 or degree numVerts-1 if (degrees[0]+degrees[2]+degrees[numVerts-1] != theGraph->N) return FALSE; // We clear all the vertex visited flags _ClearVertexVisitedFlags(theGraph, FALSE); // For each pair of image vertices, we test that there is a path // between the two vertices. If so, the visited flags of the // internal vertices along the path are marked // for (v = 0; v < numVerts; v++) for (w = 0; w < numVerts; w++) if (v != w) if (_TestPath(theGraph, imageVerts[v], imageVerts[w]) != TRUE) return FALSE; // The visited flags should have marked only degree two vertices, // so for every marked vertex, we subtract one from the count of // the degree two vertices. 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 image vertices, then there are no extra pieces of the graph in theGraph. Specifically, the prior tests identify a K_5 and ensure that nothing else could exist in the graph except extra degree 2 vertices, which must be joined in a cycle so that all are degree 2. */ return degrees[2] == 0 ? TRUE : FALSE; }
/******************************************************************** _K33Search_InitStructures() ********************************************************************/ int _K33Search_InitStructures(K33SearchContext *context) { #if NIL == 0 || NIL == -1 memset(context->VI, NIL_CHAR, gp_PrimaryVertexIndexBound(context->theGraph) * sizeof(K33Search_VertexInfo)); memset(context->E, NIL_CHAR, gp_EdgeIndexBound(context->theGraph) * sizeof(K33Search_EdgeRec)); #else graphP theGraph = context->theGraph; int v, e, Esize; if (theGraph->N <= 0) return OK; for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v); v++) _K33Search_InitVertexInfo(context, v); Esize = gp_EdgeIndexBound(theGraph); for (e = gp_GetFirstEdge(theGraph); e < Esize; e++) _K33Search_InitEdgeRec(context, e); #endif 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 gp_ColorVertices(graphP theGraph) { ColorVerticesContext *context = NULL; int v, deg; int u=0, w=0, contractible; // Attach the algorithm if it is not already attached if (gp_AttachColorVertices(theGraph) != OK) return NOTOK; // Ensure there is enough stack to perform this operation. // At a maximum, the graph reduction will push 7N+M integers. // One integer is pushed per edge that is hidden. Plus, whether // a vertex is hidden or identified with another vertex, 7 integers // are used to store enough information to restore it. if (sp_NonEmpty(theGraph->theStack)) return NOTOK; if (sp_GetCapacity(theGraph->theStack) < 7*theGraph->N + theGraph->M) { stackP newStack = sp_New(7*theGraph->N + theGraph->M); if (newStack == NULL) return NOTOK; sp_Free(&theGraph->theStack); theGraph->theStack = newStack; } // Get the extension context and reinitialize it if necessary gp_FindExtension(theGraph, COLORVERTICES_ID, (void *)&context); if (context->color[0] > -1) _ColorVertices_Reinitialize(context); // Initialize the degree lists, and provide a color for any trivial vertices for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v); v++) { deg = gp_GetVertexDegree(theGraph, v); _AddVertexToDegList(context, theGraph, v, deg); if (deg == 0) context->color[v] = 0; } // Initialize the vertex visited flags so they can be used during reductions _ClearVertexVisitedFlags(theGraph, FALSE); // Reduce the graph using minimum degree selection while (context->numVerticesToReduce > 0) { v = _GetVertexToReduce(context, theGraph); // Find out if v is contractible and the neighbors to contract contractible = _GetContractibleNeighbors(context, v, &u, &w); // Remove the vertex from the graph. This calls the fpHideEdge // overload, which performs the correct _RemoveVertexFromDegList() // and _AddVertexToDegList() operations on v and its neighbors. if (gp_HideVertex(theGraph, v) != OK) return NOTOK; // If v was contractibile, then identify u and w if (contractible) { if (gp_IdentifyVertices(theGraph, u, w, NIL) != OK) return NOTOK; } } // Restore the graph one vertex at a time, coloring each vertex distinctly // from its neighbors as it is restored. context->colorDetector = (int *) calloc(theGraph->N, sizeof(int)); if (context->colorDetector == NULL) return NOTOK; if (gp_RestoreVertices(theGraph) != OK) return NOTOK; free(context->colorDetector); context->colorDetector = NULL; return OK; }
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 _CheckEmbeddingFacialIntegrity(graphP theGraph) { stackP theStack = theGraph->theStack; int EsizeOccupied, v, e, eTwin, eStart, eNext, NumFaces, connectedComponents; if (theGraph == NULL) return NOTOK; /* The stack need only contain 2M entries, one for each edge record. With max M at 3N, this amounts to 6N integers of space. The embedding structure already contains this stack, so we just make sure it starts out empty. */ sp_ClearStack(theStack); /* Push all arcs and set them to unvisited */ EsizeOccupied = gp_EdgeInUseIndexBound(theGraph); for (e = gp_GetFirstEdge(theGraph); e < EsizeOccupied; e+=2) { // Except skip edge holes if (gp_EdgeInUse(theGraph, e)) { sp_Push(theStack, e); gp_ClearEdgeVisited(theGraph, e); eTwin = gp_GetTwinArc(theGraph, e); sp_Push(theStack, eTwin); gp_ClearEdgeVisited(theGraph, eTwin); } } // There are M edges, so we better have pushed 2M arcs just now // i.e. testing that the continue above skipped only edge holes if (sp_GetCurrentSize(theStack) != 2*theGraph->M) return NOTOK; /* Read faces until every arc is used */ NumFaces = 0; while (sp_NonEmpty(theStack)) { /* Get an arc; if it has already been used by a face, then don't use it to traverse a new face */ sp_Pop(theStack, eStart); if (gp_GetEdgeVisited(theGraph, eStart)) continue; e = eStart; do { eNext = gp_GetNextArcCircular(theGraph, gp_GetTwinArc(theGraph, e)); if (gp_GetEdgeVisited(theGraph, eNext)) return NOTOK; gp_SetEdgeVisited(theGraph, eNext); e = eNext; } while (e != eStart); NumFaces++; } /* Count the external face once rather than once per connected component; each connected component is detected by the fact that it has no DFS parent, except in the case of isolated vertices, no face was counted so we do not subtract one. */ connectedComponents = 0; for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v); v++) { if (gp_IsDFSTreeRoot(theGraph, v)) { if (gp_GetVertexDegree(theGraph, v) > 0) NumFaces--; connectedComponents++; } } NumFaces++; /* Test number of faces using the extended Euler's formula. For connected components, Euler's formula is f=m-n+2, but for disconnected graphs it is extended to f=m-n+1+c where c is the number of connected components.*/ return NumFaces == theGraph->M - theGraph->N + 1 + connectedComponents ? OK : NOTOK; }