Path: blob/master/sage/graphs/planarity/graphK33Search_Extensions.c
4069 views
/*1Planarity-Related Graph Algorithms Project2Copyright (c) 1997-2010, John M. Boyer3All rights reserved. Includes a reference implementation of the following:45* John M. Boyer. "Simplified O(n) Algorithms for Planar Graph Embedding,6Kuratowski Subgraph Isolation, and Related Problems". Ph.D. Dissertation,7University of Victoria, 2001.89* John M. Boyer and Wendy J. Myrvold. "On the Cutting Edge: Simplified O(n)10Planarity by Edge Addition". Journal of Graph Algorithms and Applications,11Vol. 8, No. 3, pp. 241-273, 2004.1213* John M. Boyer. "A New Method for Efficiently Generating Planar Graph14Visibility Representations". In P. Eades and P. Healy, editors,15Proceedings of the 13th International Conference on Graph Drawing 2005,16Lecture Notes Comput. Sci., Volume 3843, pp. 508-511, Springer-Verlag, 2006.1718Redistribution and use in source and binary forms, with or without modification,19are permitted provided that the following conditions are met:2021* Redistributions of source code must retain the above copyright notice, this22list of conditions and the following disclaimer.2324* Redistributions in binary form must reproduce the above copyright notice, this25list of conditions and the following disclaimer in the documentation and/or26other materials provided with the distribution.2728* Neither the name of the Planarity-Related Graph Algorithms Project nor the names29of its contributors may be used to endorse or promote products derived from this30software without specific prior written permission.3132THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"33AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE34IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE35DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR36ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES37(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;38LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON39ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT40(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS41SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.42*/4344#include <stdlib.h>4546#include "graphK33Search.private.h"47#include "graphK33Search.h"4849extern int _SearchForMergeBlocker(graphP theGraph, K33SearchContext *context, int I, int *pMergeBlocker);50extern int _SearchForK33(graphP theGraph, int I);5152extern int _TestForK33GraphObstruction(graphP theGraph, int *degrees, int *imageVerts);53extern int _getImageVertices(graphP theGraph, int *degrees, int maxDegree,54int *imageVerts, int maxNumImageVerts);55extern int _TestSubgraph(graphP theSubgraph, graphP theGraph);5657/* Forward declarations of local functions */5859void _K33Search_ClearStructures(K33SearchContext *context);60int _K33Search_CreateStructures(K33SearchContext *context);61int _K33Search_InitStructures(K33SearchContext *context);6263/* Forward declarations of overloading functions */6465int _K33Search_CreateFwdArcLists(graphP theGraph);66void _K33Search_CreateDFSTreeEmbedding(graphP theGraph);67void _K33Search_EmbedBackEdgeToDescendant(graphP theGraph, int RootSide, int RootVertex, int W, int WPrevLink);68int _K33Search_MergeBicomps(graphP theGraph, int I, int RootVertex, int W, int WPrevLink);69int _K33Search_MarkDFSPath(graphP theGraph, int ancestor, int descendant);70int _K33Search_HandleBlockedEmbedIteration(graphP theGraph, int I);71int _K33Search_EmbedPostprocess(graphP theGraph, int I, int edgeEmbeddingResult);72int _K33Search_CheckEmbeddingIntegrity(graphP theGraph, graphP origGraph);73int _K33Search_CheckObstructionIntegrity(graphP theGraph, graphP origGraph);7475void _K33Search_InitGraphNode(graphP theGraph, int I);76void _InitK33SearchGraphNode(K33SearchContext *context, int I);77void _K33Search_InitVertexRec(graphP theGraph, int I);78void _InitK33SearchVertexRec(K33SearchContext *context, int I);7980int _K33Search_InitGraph(graphP theGraph, int N);81void _K33Search_ReinitializeGraph(graphP theGraph);82int _K33Search_EnsureArcCapacity(graphP theGraph, int requiredArcCapacity);8384/* Forward declarations of functions used by the extension system */8586void *_K33Search_DupContext(void *pContext, void *theGraph);87void _K33Search_FreeContext(void *);8889/****************************************************************************90* K33SEARCH_ID - the variable used to hold the integer identifier for this91* extension, enabling this feature's extension context to be distinguished92* from other features' extension contexts that may be attached to a graph.93****************************************************************************/9495int K33SEARCH_ID = 0;9697/****************************************************************************98gp_AttachK33Search()99100This function adjusts the graph data structure to attach the K3,3 search101feature.102****************************************************************************/103104int gp_AttachK33Search(graphP theGraph)105{106K33SearchContext *context = NULL;107108// If the K3,3 search feature has already been attached to the graph,109// then there is no need to attach it again110gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context);111if (context != NULL)112{113return OK;114}115116// Allocate a new extension context117context = (K33SearchContext *) malloc(sizeof(K33SearchContext));118if (context == NULL)119{120return NOTOK;121}122123// First, tell the context that it is not initialized124context->initialized = 0;125126// Save a pointer to theGraph in the context127context->theGraph = theGraph;128129// Put the overload functions into the context function table.130// gp_AddExtension will overload the graph's functions with these, and131// return the base function pointers in the context function table132memset(&context->functions, 0, sizeof(graphFunctionTable));133134context->functions.fpCreateFwdArcLists = _K33Search_CreateFwdArcLists;135context->functions.fpCreateDFSTreeEmbedding = _K33Search_CreateDFSTreeEmbedding;136context->functions.fpEmbedBackEdgeToDescendant = _K33Search_EmbedBackEdgeToDescendant;137context->functions.fpMergeBicomps = _K33Search_MergeBicomps;138context->functions.fpMarkDFSPath = _K33Search_MarkDFSPath;139context->functions.fpHandleBlockedEmbedIteration = _K33Search_HandleBlockedEmbedIteration;140context->functions.fpEmbedPostprocess = _K33Search_EmbedPostprocess;141context->functions.fpCheckEmbeddingIntegrity = _K33Search_CheckEmbeddingIntegrity;142context->functions.fpCheckObstructionIntegrity = _K33Search_CheckObstructionIntegrity;143144context->functions.fpInitGraphNode = _K33Search_InitGraphNode;145context->functions.fpInitVertexRec = _K33Search_InitVertexRec;146147context->functions.fpInitGraph = _K33Search_InitGraph;148context->functions.fpReinitializeGraph = _K33Search_ReinitializeGraph;149context->functions.fpEnsureArcCapacity = _K33Search_EnsureArcCapacity;150151_K33Search_ClearStructures(context);152153// Store the K33 search context, including the data structure and the154// function pointers, as an extension of the graph155if (gp_AddExtension(theGraph, &K33SEARCH_ID, (void *) context,156_K33Search_DupContext, _K33Search_FreeContext,157&context->functions) != OK)158{159_K33Search_FreeContext(context);160return NOTOK;161}162163// Create the K33-specific structures if the size of the graph is known164// Attach functions are always invoked after gp_New(), but if a graph165// extension must be attached before gp_Read(), then the attachment166// also happens before gp_InitGraph(), which means N==0.167// However, sometimes a feature is attached after gp_InitGraph(), in168// which case N > 0169if (theGraph->N > 0)170{171if (_K33Search_CreateStructures(context) != OK ||172_K33Search_InitStructures(context) != OK)173{174_K33Search_FreeContext(context);175return NOTOK;176}177}178179return OK;180}181182/********************************************************************183gp_DetachK33Search()184********************************************************************/185186int gp_DetachK33Search(graphP theGraph)187{188return gp_RemoveExtension(theGraph, K33SEARCH_ID);189}190191/********************************************************************192_K33Search_ClearStructures()193********************************************************************/194195void _K33Search_ClearStructures(K33SearchContext *context)196{197if (!context->initialized)198{199// Before initialization, the pointers are stray, not NULL200// Once NULL or allocated, free() or LCFree() can do the job201context->sortedDFSChildLists = NULL;202context->G = NULL;203context->V = NULL;204205context->initialized = 1;206}207else208{209LCFree(&context->sortedDFSChildLists);210if (context->G != NULL)211{212free(context->G);213context->G = NULL;214}215if (context->V != NULL)216{217free(context->V);218context->V = NULL;219}220}221}222223/********************************************************************224_K33Search_CreateStructures()225Create uninitialized structures for the vertex and graph node226levels, and initialized structures for the graph level227********************************************************************/228int _K33Search_CreateStructures(K33SearchContext *context)229{230int N = context->theGraph->N;231int Gsize = context->theGraph->edgeOffset + context->theGraph->arcCapacity;232233if (N <= 0)234return NOTOK;235236if ((context->sortedDFSChildLists = LCNew(context->theGraph->N)) == NULL ||237(context->G = (K33Search_GraphNodeP) malloc(Gsize*sizeof(K33Search_GraphNode))) == NULL ||238(context->V = (K33Search_VertexRecP) malloc(N*sizeof(K33Search_VertexRec))) == NULL239)240{241return NOTOK;242}243244return OK;245}246247/********************************************************************248_K33Search_InitStructures()249********************************************************************/250int _K33Search_InitStructures(K33SearchContext *context)251{252int I, N = context->theGraph->N;253int Gsize = context->theGraph->edgeOffset + context->theGraph->arcCapacity;254255if (N <= 0)256return OK;257258for (I = 0; I < Gsize; I++)259_InitK33SearchGraphNode(context, I);260261for (I = 0; I < N; I++)262_InitK33SearchVertexRec(context, I);263264return OK;265}266267/********************************************************************268********************************************************************/269270int _K33Search_InitGraph(graphP theGraph, int N)271{272K33SearchContext *context = NULL;273gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context);274275if (context == NULL)276return NOTOK;277{278theGraph->N = N;279theGraph->edgeOffset = 2*N;280if (theGraph->arcCapacity == 0)281theGraph->arcCapacity = 2*DEFAULT_EDGE_LIMIT*N;282283if (_K33Search_CreateStructures(context) != OK)284return NOTOK;285286// This call initializes the base graph structures, but it also287// initializes the custom graphnode and vertex level structures288// due to the overloads of InitGraphNode and InitVertexRec289context->functions.fpInitGraph(theGraph, N);290}291292return OK;293}294295/********************************************************************296********************************************************************/297298void _K33Search_ReinitializeGraph(graphP theGraph)299{300K33SearchContext *context = NULL;301gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context);302303if (context != NULL)304{305// Reinitialization can go much faster if the underlying306// init graph node and vertex rec functions are called,307// rather than the overloads of this module, because it308// avoids lots of unnecessary gp_FindExtension() calls.309if (theGraph->functions.fpInitGraphNode == _K33Search_InitGraphNode &&310theGraph->functions.fpInitVertexRec == _K33Search_InitVertexRec)311{312// Restore the graph function pointers313theGraph->functions.fpInitGraphNode = context->functions.fpInitGraphNode;314theGraph->functions.fpInitVertexRec = context->functions.fpInitVertexRec;315316// Reinitialize the graph317context->functions.fpReinitializeGraph(theGraph);318319// Restore the function pointers that attach this feature320theGraph->functions.fpInitGraphNode = _K33Search_InitGraphNode;321theGraph->functions.fpInitVertexRec = _K33Search_InitVertexRec;322323// Do the reinitialization that is specific to this module324_K33Search_InitStructures(context);325LCReset(context->sortedDFSChildLists);326}327328// If optimization is not possible, then just stick with what works.329// Reinitialize the graph-level structure and then invoke the330// reinitialize function.331else332{333LCReset(context->sortedDFSChildLists);334335// The underlying function fpReinitializeGraph() implicitly initializes the K33336// structures due to the overloads of fpInitGraphNode() and fpInitVertexRec().337// It just does so less efficiently because each invocation of InitGraphNode338// and InitVertexRec has to look up the extension again.339//// _K33Search_InitStructures(context);340context->functions.fpReinitializeGraph(theGraph);341}342}343}344345/********************************************************************346The current implementation does not support an increase of arc347(edge record) capacity once the extension is attached to the graph348data structure. This is only due to not being necessary to support.349For now, it is easy to ensure the correct capacity before attaching350the extension, but support could be added later if there is some351reason to do so.352********************************************************************/353354int _K33Search_EnsureArcCapacity(graphP theGraph, int requiredArcCapacity)355{356return NOTOK;357}358359/********************************************************************360_K33Search_DupContext()361********************************************************************/362363void *_K33Search_DupContext(void *pContext, void *theGraph)364{365K33SearchContext *context = (K33SearchContext *) pContext;366K33SearchContext *newContext = (K33SearchContext *) malloc(sizeof(K33SearchContext));367368if (newContext != NULL)369{370int N = ((graphP) theGraph)->N;371int Gsize = ((graphP) theGraph)->edgeOffset + ((graphP) theGraph)->arcCapacity;372373*newContext = *context;374375newContext->theGraph = (graphP) theGraph;376377newContext->initialized = 0;378_K33Search_ClearStructures(newContext);379if (N > 0)380{381if (_K33Search_CreateStructures(newContext) != OK)382{383_K33Search_FreeContext(newContext);384return NULL;385}386387LCCopy(newContext->sortedDFSChildLists, context->sortedDFSChildLists);388memcpy(newContext->G, context->G, Gsize*sizeof(K33Search_GraphNode));389memcpy(newContext->V, context->V, N*sizeof(K33Search_VertexRec));390}391}392393return newContext;394}395396/********************************************************************397_K33Search_FreeContext()398********************************************************************/399400void _K33Search_FreeContext(void *pContext)401{402K33SearchContext *context = (K33SearchContext *) pContext;403404_K33Search_ClearStructures(context);405free(pContext);406}407408/********************************************************************409_K33Search_CreateFwdArcLists()410411Puts the forward arcs (back edges from a vertex to its descendants)412into a circular list indicated by the fwdArcList member, a task413simplified by the fact that they have already been placed in414succession at the end of the adjacency list.415416For K3,3 search, the forward edges must be sorted. The sort is linear417time, but it is a little slower, so we avoid this cost for the other418planarity-related algorithms.419420Returns OK on success, NOTOK on internal code failure421********************************************************************/422423int _K33Search_CreateFwdArcLists(graphP theGraph)424{425K33SearchContext *context = NULL;426427gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context);428if (context == NULL)429return NOTOK;430431// For isolating a K_{3,3} homeomorph, we need the forward edges432// of each vertex to be in sorted order by DFI of descendants.433// Otherwise we just drop through to the normal processing...434435if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK33)436{437int I, Jcur, Jnext, ancestor;438439// for each vertex v in order, we follow each of its back edges440// to the twin forward edge in an ancestor u, then we move441// the forward edge to the fwdArcList of u. Since this loop442// processes vertices in order, the fwdArcList of each vertex443// will be in order by the neighbor indicated by the forward edges.444445for (I=0; I < theGraph->N; I++)446{447// Skip this vertex if it has no edges448Jnext = gp_GetLastArc(theGraph, I);449if (!gp_IsArc(theGraph, Jnext))450continue;451452// Skip the forward edges, which are in succession at the453// end of the arc list (last and its predecessors)454while (theGraph->G[Jnext].type == EDGE_FORWARD)455Jnext = gp_GetPrevArc(theGraph, Jnext);456457// Now we want to put all the back arcs in a backArcList, too.458// Since we've already skipped past the forward arcs, we continue459// with the predecessor arcs until we either run out of arcs or460// we find a DFS child arc (the DFS child arcs are in succession461// at the beginning of the arc list, so when a child arc is462// encountered in the predecessor direction, then there won't be463// any more back arcs.464while (gp_IsArc(theGraph, Jnext) &&465theGraph->G[Jnext].type != EDGE_DFSCHILD)466{467Jcur = Jnext;468Jnext = gp_GetPrevArc(theGraph, Jnext);469470if (theGraph->G[Jcur].type == EDGE_BACK)471{472// Remove the back arc from I's adjacency list473gp_DetachArc(theGraph, Jcur);474475// Put the back arc in the backArcList476if (context->V[I].backArcList == NIL)477{478context->V[I].backArcList = Jcur;479gp_SetPrevArc(theGraph, Jcur, Jcur);480gp_SetNextArc(theGraph, Jcur, Jcur);481}482else483{484gp_AttachArc(theGraph, NIL, context->V[I].backArcList, 1, Jcur);485}486487// Determine the ancestor of vertex I to which Jcur connects488ancestor = theGraph->G[Jcur].v;489490// Go to the forward arc in the ancestor491Jcur = gp_GetTwinArc(theGraph, Jcur);492493// Remove the forward arc from the ancestor's adjacency list494gp_DetachArc(theGraph, Jcur);495496// Add the forward arc to the end of the fwdArcList.497if (theGraph->V[ancestor].fwdArcList == NIL)498{499theGraph->V[ancestor].fwdArcList = Jcur;500gp_SetPrevArc(theGraph, Jcur, Jcur);501gp_SetNextArc(theGraph, Jcur, Jcur);502}503else504{505gp_AttachArc(theGraph, NIL, theGraph->V[ancestor].fwdArcList, 1, Jcur);506}507}508}509}510511// Since the fwdArcLists have been created, we do not fall through512// to run the superclass implementation513return OK;514}515516// If we're not actually running a K3,3 search, then we just run the517// superclass implementation518return context->functions.fpCreateFwdArcLists(theGraph);519}520521/********************************************************************522_K33Search_CreateDFSTreeEmbedding()523524This function overloads the basic planarity version in the manner525explained by the comments below. Once the extra behavior is526performed, the basic planarity version is invoked.527********************************************************************/528529void _K33Search_CreateDFSTreeEmbedding(graphP theGraph)530{531K33SearchContext *context = NULL;532gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context);533534if (context != NULL)535{536// When searching for K_{3,3} homeomorphs, we need the537// list of DFS children for each vertex, which gets lost538// during the initial tree embedding (each DFS tree child539// arc is moved to the root copy of the vertex)540541if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK33)542{543int I, J, N;544545N = theGraph->N;546547for (I=0; I<N; I++)548{549J = gp_GetFirstArc(theGraph, I);550551// If a vertex has any DFS children, the edges552// to them are stored in descending order of553// the DFI's along the successor arc pointers, so554// we traverse them and prepend each to the555// ascending order sortedDFSChildList556557while (theGraph->G[J].type == EDGE_DFSCHILD)558{559context->V[I].sortedDFSChildList =560LCPrepend(context->sortedDFSChildLists,561context->V[I].sortedDFSChildList,562theGraph->G[J].v);563564J = gp_GetNextArc(theGraph, J);565}566}567}568569// Invoke the superclass version of the function570context->functions.fpCreateDFSTreeEmbedding(theGraph);571}572}573574/********************************************************************575_K33Search_EmbedBackEdgeToDescendant()576577The forward and back arcs of the cycle edge are embedded by the planarity578version of this function.579However, for K_{3,3} subgraph homeomorphism, we also maintain the580list of unembedded back arcs, so we need to remove the back arc from581that list since it is now being put back into the adjacency list.582********************************************************************/583584void _K33Search_EmbedBackEdgeToDescendant(graphP theGraph, int RootSide, int RootVertex, int W, int WPrevLink)585{586K33SearchContext *context = NULL;587gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context);588589if (context != NULL)590{591// K33 search may have been attached, but not enabled592if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK33)593{594// Get the fwdArc from the adjacentTo field, and use it to get the backArc595int backArc = gp_GetTwinArc(theGraph, theGraph->V[W].adjacentTo);596597// Remove the backArc from the backArcList598if (context->V[W].backArcList == backArc)599{600if (gp_GetNextArc(theGraph, backArc) == backArc)601context->V[W].backArcList = NIL;602else context->V[W].backArcList = gp_GetNextArc(theGraph, backArc);603}604605gp_SetNextArc(theGraph, gp_GetPrevArc(theGraph, backArc), gp_GetNextArc(theGraph, backArc));606gp_SetPrevArc(theGraph, gp_GetNextArc(theGraph, backArc), gp_GetPrevArc(theGraph, backArc));607}608609// Invoke the superclass version of the function610context->functions.fpEmbedBackEdgeToDescendant(theGraph, RootSide, RootVertex, W, WPrevLink);611}612}613614/********************************************************************615616This override of _MergeBicomps() detects a special merge block617that indicates a K3,3 can be found. The merge blocker is an618optimization needed for one case for which detecting a K3,3619could not be done in linear time.620621Returns OK for a successful merge, NOTOK on an internal failure,622or NONEMBEDDABLE if the merge is blocked623********************************************************************/624625int _K33Search_MergeBicomps(graphP theGraph, int I, int RootVertex, int W, int WPrevLink)626{627K33SearchContext *context = NULL;628gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context);629630if (context != NULL)631{632/* If the merge is blocked, then the Walkdown is terminated so a633K3,3 can be isolated by _SearchForK33() */634635if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK33)636{637int mergeBlocker;638639// We want to test all merge points on the stack640// as well as W, since the connection will go641// from W. So we push W as a 'degenerate' merge point.642sp_Push2(theGraph->theStack, W, WPrevLink);643sp_Push2(theGraph->theStack, NIL, NIL);644645_SearchForMergeBlocker(theGraph, context, I, &mergeBlocker);646647// If we find a merge blocker, then we return with648// the stack intact including W so that the merge649// blocked vertex can be easily found.650if (mergeBlocker != NIL)651return NONEMBEDDABLE;652653// If no merge blocker was found, then remove654// W from the stack.655sp_Pop2(theGraph->theStack, W, WPrevLink);656sp_Pop2(theGraph->theStack, W, WPrevLink);657}658659// If the merge was not blocked, then we perform the merge660// When not doing a K3,3 search, then the merge is not661// blocked as far as the K3,3 search method is concerned662// Another algorithms could overload MergeBicomps and block663// merges under certain conditions, but those would be based664// on data maintained by the extension that implements the665// other algorithm-- if *that* algorithm is the one being run666return context->functions.fpMergeBicomps(theGraph, I, RootVertex, W, WPrevLink);667}668669return NOTOK;670}671672/********************************************************************673********************************************************************/674675void _K33Search_InitGraphNode(graphP theGraph, int I)676{677K33SearchContext *context = NULL;678gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context);679680if (context != NULL)681{682context->functions.fpInitGraphNode(theGraph, I);683_InitK33SearchGraphNode(context, I);684}685}686687void _InitK33SearchGraphNode(K33SearchContext *context, int I)688{689context->G[I].noStraddle = NIL;690context->G[I].pathConnector = NIL;691}692693/********************************************************************694********************************************************************/695696void _K33Search_InitVertexRec(graphP theGraph, int I)697{698K33SearchContext *context = NULL;699gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context);700701if (context != NULL)702{703context->functions.fpInitVertexRec(theGraph, I);704_InitK33SearchVertexRec(context, I);705}706}707708void _InitK33SearchVertexRec(K33SearchContext *context, int I)709{710context->V[I].sortedDFSChildList = NIL;711context->V[I].backArcList = NIL;712context->V[I].externalConnectionAncestor = NIL;713context->V[I].mergeBlocker = NIL;714}715716/********************************************************************717// This function used to be implemented by going to each718// vertex, asking for its DFS parent, then finding the719// edge that lead to that DFS parent and marking it.720// However, the K3,3 search performs a certain bicomp721// reduction that is required to preserve the essential722// structure of the DFS tree. As a result, sometimes a723// DFSParent has been reduced out of the graph, but the724// tree edge leads to the nearest ancestor still in the725// graph. So, when we want to leave a vertex, we search726// for the DFS tree edge to the "parent" (nearest ancestor).727// then we mark the edge and use it to go up to the "parent".728********************************************************************/729730int _K33Search_MarkDFSPath(graphP theGraph, int ancestor, int descendant)731{732int J, parent, N;733734N = theGraph->N;735736/* If we are marking from a root vertex upward, then go up to the parent737copy before starting the loop */738739if (descendant >= N)740descendant = theGraph->V[descendant-N].DFSParent;741742/* Mark the lowest vertex (the one with the highest number). */743744theGraph->G[descendant].visited = 1;745746/* Mark all ancestors of the lowest vertex, and the edges used to reach747them, up to the given ancestor vertex. */748749while (descendant != ancestor)750{751if (descendant == NIL)752return NOTOK;753754/* If we are at a bicomp root, then ascend to its parent copy and755mark it as visited. */756757if (descendant >= N)758{759parent = theGraph->V[descendant-N].DFSParent;760}761762/* If we are on a regular, non-virtual vertex then get the edge to763the parent, mark the edge, then fall through to the code764that marks the parent vertex. */765else766{767768/* Scan the edges for the one marked as the DFS parent */769770parent = NIL;771J = gp_GetFirstArc(theGraph, descendant);772while (gp_IsArc(theGraph, J))773{774if (theGraph->G[J].type == EDGE_DFSPARENT)775{776parent = theGraph->G[J].v;777break;778}779J = gp_GetNextArc(theGraph, J);780}781782/* If the desired edge was not found, then the data structure is783corrupt, so bail out. */784785if (parent == NIL)786return NOTOK;787788/* Mark the edge */789790theGraph->G[J].visited = 1;791theGraph->G[gp_GetTwinArc(theGraph, J)].visited = 1;792}793794/* Mark the parent, then hop to the parent and reiterate */795796theGraph->G[parent].visited = 1;797descendant = parent;798}799800return OK;801}802803/********************************************************************804********************************************************************/805806int _K33Search_HandleBlockedEmbedIteration(graphP theGraph, int I)807{808if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK33)809return _SearchForK33(theGraph, I);810811else812{813K33SearchContext *context = NULL;814gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context);815816if (context != NULL)817{818return context->functions.fpHandleBlockedEmbedIteration(theGraph, I);819}820}821822return NOTOK;823}824825/********************************************************************826********************************************************************/827828int _K33Search_EmbedPostprocess(graphP theGraph, int I, int edgeEmbeddingResult)829{830// For K3,3 search, we just return the edge embedding result because the831// search result has been obtained already.832if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK33)833{834return edgeEmbeddingResult;835}836837// When not searching for K3,3, we let the superclass do the work838else839{840K33SearchContext *context = NULL;841gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context);842843if (context != NULL)844{845return context->functions.fpEmbedPostprocess(theGraph, I, edgeEmbeddingResult);846}847}848849return NOTOK;850}851852/********************************************************************853********************************************************************/854855int _K33Search_CheckEmbeddingIntegrity(graphP theGraph, graphP origGraph)856{857if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK33)858{859return OK;860}861862// When not searching for K3,3, we let the superclass do the work863else864{865K33SearchContext *context = NULL;866gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context);867868if (context != NULL)869{870return context->functions.fpCheckEmbeddingIntegrity(theGraph, origGraph);871}872}873874return NOTOK;875}876877/********************************************************************878********************************************************************/879880int _K33Search_CheckObstructionIntegrity(graphP theGraph, graphP origGraph)881{882// When searching for K3,3, we ensure that theGraph is a subgraph of883// the original graph and that it contains a K3,3 homeomorph884if (theGraph->embedFlags == EMBEDFLAGS_SEARCHFORK33)885{886int degrees[5], imageVerts[6];887888if (_TestSubgraph(theGraph, origGraph) != TRUE)889{890return NOTOK;891}892893if (_getImageVertices(theGraph, degrees, 4, imageVerts, 6) != OK)894{895return NOTOK;896}897898if (_TestForK33GraphObstruction(theGraph, degrees, imageVerts) == TRUE)899{900return OK;901}902903return NOTOK;904}905906// When not searching for K3,3, we let the superclass do the work907else908{909K33SearchContext *context = NULL;910gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context);911912if (context != NULL)913{914return context->functions.fpCheckObstructionIntegrity(theGraph, origGraph);915}916}917918return NOTOK;919}920921922923