int _ColorVertices_InitGraph(graphP theGraph, int N) { ColorVerticesContext *context = NULL; gp_FindExtension(theGraph, COLORVERTICES_ID, (void *)&context); if (context == NULL) { return NOTOK; } else { theGraph->N = N; theGraph->edgeOffset = 2*N; if (theGraph->arcCapacity == 0) theGraph->arcCapacity = 2*DEFAULT_EDGE_LIMIT*N; // Create custom structures, initialized at graph level, // uninitialized at vertex and graph node levels. if (_ColorVertices_CreateStructures(context) != OK) { return NOTOK; } // This call initializes the base graph structures, but it also // initializes the custom graphnode and vertex level structures // due to the overloads of InitGraphNode and InitVertexRec context->functions.fpInitGraph(theGraph, N); } return OK; }
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 _K33Search_HandleBlockedBicomp(graphP theGraph, int v, int RootVertex, int R) { K33SearchContext *context = NULL; gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context); if (context == NULL) return NOTOK; if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK33) { // If R is the root of a descendant bicomp of v, we push it, but then we know the search for K3,3 // will be successful and return NONEMBEDDABLE because this condition corresponds to minor A, which // is a K3,3. Thus, an "OK to proceed with Walkdown searching elsewhere" result cannot happen, // so we don't have to test for it to detect if we have to pop these two back off the stack. if (R != RootVertex) sp_Push2(theGraph->theStack, R, 0); // The possible results here are NONEMBEDDABLE if a K3,3 homeomorph is found, or OK if only // a K5 was found and unblocked such that it is OK for the Walkdown to continue searching // elsewhere. Note that the OK result can only happen if RootVertex==R since minor E can only // happen on a child bicomp of vertex v, not a descendant bicomp. return _SearchForK33InBicomp(theGraph, context, v, RootVertex); } else { return context->functions.fpHandleBlockedBicomp(theGraph, v, RootVertex, R); } return NOTOK; }
void _K33Search_InitVertexRec(graphP theGraph, int I) { K33SearchContext *context = NULL; gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context); if (context != NULL) { context->functions.fpInitVertexRec(theGraph, I); _InitK33SearchVertexRec(context, I); } }
int gp_AddExtension(graphP theGraph, int *pModuleID, void *context, void *(*dupContext)(void *, void *), void (*freeContext)(void *), graphFunctionTableP functions) { graphExtensionP newExtension = NULL; if (theGraph == NULL || pModuleID == NULL || context == NULL || dupContext == NULL || freeContext == NULL || functions == NULL) { return NOTOK; } // If the extension already exists, then don't redefine it. if (gp_FindExtension(theGraph, *pModuleID, NULL) == TRUE) { return NOTOK; } // Assign a unique ID to the extension if it does not already have one if (*pModuleID == 0) { *pModuleID = ++moduleIDGenerator; } // Allocate the new extension if ((newExtension = (graphExtensionP) malloc(sizeof(graphExtension))) == NULL) { return NOTOK; } // Assign the data payload of the extension newExtension->moduleID = *pModuleID; newExtension->context = context; newExtension->dupContext = dupContext; newExtension->freeContext = freeContext; newExtension->functions = functions; _OverloadFunctions(theGraph, functions); // Make the new linkages newExtension->next = (struct graphExtension *) theGraph->extensions; theGraph->extensions = newExtension; // The new extension was successfully added return OK; }
void _K4Search_ReinitializeGraph(graphP theGraph) { K4SearchContext *context = NULL; gp_FindExtension(theGraph, K4SEARCH_ID, (void *)&context); if (context != NULL) { // Reinitialize the graph context->functions.fpReinitializeGraph(theGraph); // Do the reinitialization that is specific to this module _K4Search_InitStructures(context); } }
int _K33Search_MergeBicomps(graphP theGraph, int v, int RootVertex, int W, int WPrevLink) { K33SearchContext *context = NULL; gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context); if (context != NULL) { /* If the merge is blocked, then a K_{3,3} homeomorph is isolated, and NONEMBEDDABLE is returned so that the Walkdown terminates */ if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK33) { int mergeBlocker; // We want to test all merge points on the stack // as well as W, since the connection will go // from W. So we push W as a 'degenerate' merge point. sp_Push2(theGraph->theStack, W, WPrevLink); sp_Push2(theGraph->theStack, NIL, NIL); if (_SearchForMergeBlocker(theGraph, context, v, &mergeBlocker) != OK) return NOTOK; if (gp_IsVertex(mergeBlocker)) { if (_FindK33WithMergeBlocker(theGraph, context, v, mergeBlocker) != OK) return NOTOK; return NONEMBEDDABLE; } // If no merge blocker was found, then remove W from the stack. sp_Pop2(theGraph->theStack, W, WPrevLink); sp_Pop2(theGraph->theStack, W, WPrevLink); } // If the merge was not blocked, then we perform the merge // When not doing a K3,3 search, then the merge is not // blocked as far as the K3,3 search method is concerned // Another algorithms could overload MergeBicomps and block // merges under certain conditions, but those would be based // on data maintained by the extension that implements the // other algorithm-- if *that* algorithm is the one being run return context->functions.fpMergeBicomps(theGraph, v, RootVertex, W, WPrevLink); } return NOTOK; }
void _K33Search_ReinitializeGraph(graphP theGraph) { K33SearchContext *context = NULL; gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context); if (context != NULL) { // Reinitialize the graph context->functions.fpReinitializeGraph(theGraph); // Do the reinitialization that is specific to this module _K33Search_InitStructures(context); LCReset(context->separatedDFSChildLists); LCReset(context->bin); } }
/******************************************************************** _K33Search_MergeVertex() Overload of merge vertex that does basic behavior but also removes the DFS child associated with R from the separatedDFSChildList of W. ********************************************************************/ void _K33Search_MergeVertex(graphP theGraph, int W, int WPrevLink, int R) { K33SearchContext *context = NULL; gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context); if (context != NULL) { if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK33) { int theList = context->VI[W].separatedDFSChildList; theList = LCDelete(context->separatedDFSChildLists, theList, gp_GetDFSChildFromRoot(theGraph, R)); context->VI[W].separatedDFSChildList = theList; } context->functions.fpMergeVertex(theGraph, W, WPrevLink, R); } }
void _K33Search_ReinitializeGraph(graphP theGraph) { K33SearchContext *context = NULL; gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context); if (context != NULL) { // Reinitialization can go much faster if the underlying // init graph node and vertex rec functions are called, // rather than the overloads of this module, because it // avoids lots of unnecessary gp_FindExtension() calls. if (theGraph->functions.fpInitGraphNode == _K33Search_InitGraphNode && theGraph->functions.fpInitVertexRec == _K33Search_InitVertexRec) { // Restore the graph function pointers theGraph->functions.fpInitGraphNode = context->functions.fpInitGraphNode; theGraph->functions.fpInitVertexRec = context->functions.fpInitVertexRec; // Reinitialize the graph context->functions.fpReinitializeGraph(theGraph); // Restore the function pointers that attach this feature theGraph->functions.fpInitGraphNode = _K33Search_InitGraphNode; theGraph->functions.fpInitVertexRec = _K33Search_InitVertexRec; // Do the reinitialization that is specific to this module _K33Search_InitStructures(context); LCReset(context->sortedDFSChildLists); } // If optimization is not possible, then just stick with what works. // Reinitialize the graph-level structure and then invoke the // reinitialize function. else { LCReset(context->sortedDFSChildLists); // The underlying function fpReinitializeGraph() implicitly initializes the K33 // structures due to the overloads of fpInitGraphNode() and fpInitVertexRec(). // It just does so less efficiently because each invocation of InitGraphNode // and InitVertexRec has to look up the extension again. //// _K33Search_InitStructures(context); context->functions.fpReinitializeGraph(theGraph); } } }
int _K23Search_HandleBlockedEmbedIteration(graphP theGraph, int I) { if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK23) return _SearchForK23(theGraph, I); else { K23SearchContext *context = NULL; gp_FindExtension(theGraph, K23SEARCH_ID, (void *)&context); if (context != NULL) { return context->functions.fpHandleBlockedEmbedIteration(theGraph, I); } } return NOTOK; }
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 gp_AttachK23Search(graphP theGraph) { K23SearchContext *context = NULL; // If the K2,3 search feature has already been attached to the graph // then there is no need to attach it again gp_FindExtension(theGraph, K23SEARCH_ID, (void *)&context); if (context != NULL) { return OK; } // Allocate a new extension context context = (K23SearchContext *) malloc(sizeof(K23SearchContext)); if (context == NULL) { return NOTOK; } // Put the overload functions into the context function table. // gp_AddExtension will overload the graph's functions with these, and // return the base function pointers in the context function table memset(&context->functions, 0, sizeof(graphFunctionTable)); context->functions.fpHandleBlockedEmbedIteration = _K23Search_HandleBlockedEmbedIteration; context->functions.fpEmbedPostprocess = _K23Search_EmbedPostprocess; context->functions.fpCheckEmbeddingIntegrity = _K23Search_CheckEmbeddingIntegrity; context->functions.fpCheckObstructionIntegrity = _K23Search_CheckObstructionIntegrity; // Store the K23 search context, including the data structure and the // function pointers, as an extension of the graph if (gp_AddExtension(theGraph, &K23SEARCH_ID, (void *) context, _K23Search_DupContext, _K23Search_FreeContext, &context->functions) != OK) { _K23Search_FreeContext(context); return NOTOK; } return OK; }
int _K33Search_CheckEmbeddingIntegrity(graphP theGraph, graphP origGraph) { if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK33) { return OK; } // When not searching for K3,3, we let the superclass do the work else { K33SearchContext *context = NULL; gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context); if (context != NULL) { return context->functions.fpCheckEmbeddingIntegrity(theGraph, origGraph); } } return NOTOK; }
int _K33Search_EmbeddingInitialize(graphP theGraph) { K33SearchContext *context = NULL; gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context); if (context != NULL) { if (context->functions.fpEmbeddingInitialize(theGraph) != OK) return NOTOK; if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK33) { _CreateBackArcLists(theGraph, context); _CreateSeparatedDFSChildLists(theGraph, context); } return OK; } return NOTOK; }
int _K33Search_InitGraph(graphP theGraph, int N) { K33SearchContext *context = NULL; gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context); if (context == NULL) return NOTOK; theGraph->N = N; theGraph->NV = N; if (theGraph->arcCapacity == 0) theGraph->arcCapacity = 2*DEFAULT_EDGE_LIMIT*N; if (_K33Search_CreateStructures(context) != OK || _K33Search_InitStructures(context) != OK) return NOTOK; context->functions.fpInitGraph(theGraph, N); return OK; }
int _K33Search_CheckObstructionIntegrity(graphP theGraph, graphP origGraph) { // When searching for K3,3, we ensure that theGraph is a subgraph of // the original graph and that it contains a K3,3 homeomorph if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK33) { int degrees[5], imageVerts[6]; if (_TestSubgraph(theGraph, origGraph) != TRUE) { return NOTOK; } if (_getImageVertices(theGraph, degrees, 4, imageVerts, 6) != OK) { return NOTOK; } if (_TestForK33GraphObstruction(theGraph, degrees, imageVerts) == TRUE) { return OK; } return NOTOK; } // When not searching for K3,3, we let the superclass do the work else { K33SearchContext *context = NULL; gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context); if (context != NULL) { return context->functions.fpCheckObstructionIntegrity(theGraph, origGraph); } } return NOTOK; }
int _K33Search_EmbedPostprocess(graphP theGraph, int v, int edgeEmbeddingResult) { // For K3,3 search, we just return the edge embedding result because the // search result has been obtained already. if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK33) { return edgeEmbeddingResult; } // When not searching for K3,3, we let the superclass do the work else { K33SearchContext *context = NULL; gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context); if (context != NULL) { return context->functions.fpEmbedPostprocess(theGraph, v, edgeEmbeddingResult); } } return NOTOK; }
int _K33Search_InitGraph(graphP theGraph, int N) { K33SearchContext *context = NULL; gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context); if (context == NULL) return NOTOK; { theGraph->N = N; theGraph->edgeOffset = 2*N; if (theGraph->arcCapacity == 0) theGraph->arcCapacity = 2*DEFAULT_EDGE_LIMIT*N; if (_K33Search_CreateStructures(context) != OK) return NOTOK; // This call initializes the base graph structures, but it also // initializes the custom graphnode and vertex level structures // due to the overloads of InitGraphNode and InitVertexRec context->functions.fpInitGraph(theGraph, N); } return OK; }
int _K4Search_HandleBlockedBicomp(graphP theGraph, int v, int RootVertex, int R) { K4SearchContext *context = NULL; gp_FindExtension(theGraph, K4SEARCH_ID, (void *)&context); if (context == NULL) return NOTOK; if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK4) { int RetVal = OK; // If invoked on a descendant bicomp, then we push its root then search once // since not finding a K4 homeomorph will also clear the blockage and allow // the Walkdown to continue walking down if (R != RootVertex) { sp_Push2(theGraph->theStack, R, 0); if ((RetVal = _SearchForK4InBicomp(theGraph, context, v, R)) == OK) { // If the Walkdown will be told it is OK to continue, then we have to take the descendant // bicomp root back off the stack so the Walkdown can try to descend to it again. int dummy; sp_Pop2(theGraph->theStack, R, dummy); // And we have to clear the indicator of the minor A that was reduced, since it was eliminated. theGraph->IC.minorType = 0; } } // Otherwise, if invoked on a child bicomp rooted by a virtual copy of v, // then we search for a K4 homeomorph, and if OK is returned, then that indicates // the blockage has been cleared and it is OK to Walkdown the bicomp. // But the Walkdown finished, already, so we launch it again. // If the Walkdown returns OK then all forward arcs were embedded. If NONEMBEDDABLE // is returned, then the bicomp got blocked again, so we have to reiterate the K4 search else { // If Walkdown has recursively called this handler on the bicomp rooted by RootVertex, // then it is still blocked, so we just return NONEMBEDDABLE, which causes Walkdown to // return to the loop below and signal that the loop should invoke the Walkdown again. if (context->handlingBlockedBicomp) return NONEMBEDDABLE; context->handlingBlockedBicomp = TRUE; do { // Detect whether bicomp can be used to find a K4 homeomorph. It it does, then // it returns NONEMBEDDABLE so we break the search because we found the desired K4 // If OK is returned, then the blockage was cleared and it is OK to Walkdown again. if ((RetVal = _SearchForK4InBicomp(theGraph, context, v, RootVertex)) != OK) break; // Walkdown again to embed more edges. If Walkdown returns OK, then all remaining // edges to its descendants are embedded, so we'll get out of this loop. If Walkdown // detects that it still has not embedded all the edges to descendants of the bicomp's // root edge child, then Walkdown calls this routine again, and the above non-reentrancy // code returns NONEMBEDDABLE, causing this loop to search again for a K4. theGraph->IC.minorType = 0; RetVal = theGraph->functions.fpWalkDown(theGraph, v, RootVertex); // Except if the Walkdown returns NONEMBEDDABLE due to finding a K4 homeomorph entangled // with a descendant bicomp (the R != RootVertex case above), then it was found // entangled with Minor A, so we can stop the search if minor A is detected if (theGraph->IC.minorType & MINORTYPE_A) break; } while (RetVal == NONEMBEDDABLE); context->handlingBlockedBicomp = FALSE; } return RetVal; } else { return context->functions.fpHandleBlockedBicomp(theGraph, v, RootVertex, R); } return NOTOK; }
int _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); }
/******************************************************************** gp_GetExtension() Calling this function is equivalent to invoking gp_FindExtension() except that some debuggers have difficulty stepping into a function that (properly) start by setting a local variable pointer to NULL when the debugger has watch expressions that dereference a pointer of the same name. In such cases, MyContext *context = NULL; gp_FindExtension(theGraph, MYEXTENSION_ID, &context); can be replaced by MyContext *context = gp_GetExtension(theGraph, MYEXTENSION_ID); @param theGraph - the graph whose extension list is to be searched @param moduleID - the identifier of the module whose extension context is desired @return void pointer to the extension if found, or NULL if not found. ********************************************************************/ void *gp_GetExtension(graphP theGraph, int moduleID) { void *context = NULL; int result = gp_FindExtension(theGraph, moduleID, &context); return result ? context : NULL; }
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 = 0; v < theGraph->N; v++) { deg = gp_GetVertexDegree(theGraph, v); _AddVertexToDegList(context, theGraph, v, deg); if (deg == 0) context->color[v] = 0; } // Initialize the visited flags so they can be used during reductions _FillVisitedFlags(theGraph, 0); // 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 gp_AttachK33Search(graphP theGraph) { K33SearchContext *context = NULL; // If the K3,3 search feature has already been attached to the graph, // then there is no need to attach it again gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context); if (context != NULL) { return OK; } // Allocate a new extension context context = (K33SearchContext *) malloc(sizeof(K33SearchContext)); if (context == NULL) { return NOTOK; } // First, tell the context that it is not initialized context->initialized = 0; // Save a pointer to theGraph in the context context->theGraph = theGraph; // Put the overload functions into the context function table. // gp_AddExtension will overload the graph's functions with these, and // return the base function pointers in the context function table memset(&context->functions, 0, sizeof(graphFunctionTable)); context->functions.fpEmbeddingInitialize = _K33Search_EmbeddingInitialize; context->functions.fpEmbedBackEdgeToDescendant = _K33Search_EmbedBackEdgeToDescendant; context->functions.fpMergeBicomps = _K33Search_MergeBicomps; context->functions.fpMergeVertex = _K33Search_MergeVertex; context->functions.fpHandleBlockedBicomp = _K33Search_HandleBlockedBicomp; context->functions.fpEmbedPostprocess = _K33Search_EmbedPostprocess; context->functions.fpCheckEmbeddingIntegrity = _K33Search_CheckEmbeddingIntegrity; context->functions.fpCheckObstructionIntegrity = _K33Search_CheckObstructionIntegrity; context->functions.fpInitGraph = _K33Search_InitGraph; context->functions.fpReinitializeGraph = _K33Search_ReinitializeGraph; context->functions.fpEnsureArcCapacity = _K33Search_EnsureArcCapacity; _K33Search_ClearStructures(context); // Store the K33 search context, including the data structure and the // function pointers, as an extension of the graph if (gp_AddExtension(theGraph, &K33SEARCH_ID, (void *) context, _K33Search_DupContext, _K33Search_FreeContext, &context->functions) != OK) { _K33Search_FreeContext(context); return NOTOK; } // Create the K33-specific structures if the size of the graph is known // Attach functions are always invoked after gp_New(), but if a graph // extension must be attached before gp_Read(), then the attachment // also happens before gp_InitGraph(), which means N==0. // However, sometimes a feature is attached after gp_InitGraph(), in // which case N > 0 if (theGraph->N > 0) { if (_K33Search_CreateStructures(context) != OK || _K33Search_InitStructures(context) != OK) { _K33Search_FreeContext(context); return NOTOK; } } return OK; }
char *_RenderToString(graphP theEmbedding) { DrawPlanarContext *context = NULL; gp_FindExtension(theEmbedding, DRAWPLANAR_ID, (void *) &context); if (context != NULL) { int N = theEmbedding->N; int M = theEmbedding->M; int I, J, e, Mid, Pos; char *visRep = (char *) malloc(sizeof(char) * ((M+1) * 2*N + 1)); char numBuffer[32]; if (visRep == NULL) return NULL; if (sp_NonEmpty(context->theGraph->edgeHoles)) { free(visRep); return NULL; } // Clear the space for (I = 0; I < N; I++) { for (J=0; J < M; J++) { visRep[(2*I) * (M+1) + J] = ' '; visRep[(2*I+1) * (M+1) + J] = ' '; } visRep[(2*I) * (M+1) + M] = '\n'; visRep[(2*I+1) * (M+1) + M] = '\n'; } // Draw the vertices for (I = 0; I < N; I++) { Pos = context->G[I].pos; for (J=context->G[I].start; J<=context->G[I].end; J++) visRep[(2*Pos) * (M+1) + J] = '-'; // Draw vertex label Mid = (context->G[I].start + context->G[I].end)/2; sprintf(numBuffer, "%d", I); if ((unsigned)(context->G[I].end - context->G[I].start + 1) >= strlen(numBuffer)) { strncpy(visRep + (2*Pos) * (M+1) + Mid, numBuffer, strlen(numBuffer)); } // If the vertex width is less than the label width, then fail gracefully else { if (strlen(numBuffer)==2) visRep[(2*Pos) * (M+1) + Mid] = numBuffer[0]; else visRep[(2*Pos) * (M+1) + Mid] = '*'; visRep[(2*Pos+1) * (M+1) + Mid] = numBuffer[strlen(numBuffer)-1]; } } // Draw the edges for (e=0; e<M; e++) { J = 2*N + 2*e; Pos = context->G[J].pos; for (I=context->G[J].start; I<context->G[J].end; I++) { if (I > context->G[J].start) visRep[(2*I) * (M+1) + Pos] = '|'; visRep[(2*I+1) * (M+1) + Pos] = '|'; } } // Null terminate string and return it visRep[(M+1) * 2*N] = '\0'; return visRep; } return NULL; }
int gp_AttachColorVertices(graphP theGraph) { ColorVerticesContext *context = NULL; // If the vertex coloring feature has already been attached to the graph, // then there is no need to attach it again gp_FindExtension(theGraph, COLORVERTICES_ID, (void *)&context); if (context != NULL) { return OK; } // Allocate a new extension context context = (ColorVerticesContext *) malloc(sizeof(ColorVerticesContext)); if (context == NULL) { return NOTOK; } // First, tell the context that it is not initialized context->initialized = 0; // Save a pointer to theGraph in the context context->theGraph = theGraph; // Put the overload functions into the context function table. // gp_AddExtension will overload the graph's functions with these, and // return the base function pointers in the context function table memset(&context->functions, 0, sizeof(graphFunctionTable)); context->functions.fpInitGraph = _ColorVertices_InitGraph; context->functions.fpReinitializeGraph = _ColorVertices_ReinitializeGraph; context->functions.fpReadPostprocess = _ColorVertices_ReadPostprocess; context->functions.fpWritePostprocess = _ColorVertices_WritePostprocess; context->functions.fpHideEdge = _ColorVertices_HideEdge; context->functions.fpIdentifyVertices = _ColorVertices_IdentifyVertices; context->functions.fpRestoreVertex = _ColorVertices_RestoreVertex; _ColorVertices_ClearStructures(context); // Store the context, including the data structure and the // function pointers, as an extension of the graph if (gp_AddExtension(theGraph, &COLORVERTICES_ID, (void *) context, _ColorVertices_DupContext, _ColorVertices_FreeContext, &context->functions) != OK) { _ColorVertices_FreeContext(context); return NOTOK; } // Create the algorithm-specific structures if the size of the graph is known // Attach functions are typically invoked after gp_New(), but if a graph // extension must be attached before gp_Read(), then the attachment // also happens before gp_InitGraph() because gp_Read() invokes init only // after it reads the order N of the graph. Hence, this attach call would // occur when N==0 in the case of gp_Read(). // But if a feature is attached after gp_InitGraph(), then N > 0 and so we // need to create and initialize all the custom data structures if (theGraph->N > 0) { if (_ColorVertices_CreateStructures(context) != OK || _ColorVertices_InitStructures(context) != OK) { _ColorVertices_FreeContext(context); return NOTOK; } } return OK; }