/*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#define GRAPHSTRUCTURE_C4546#include <stdlib.h>4748#include "graphStructures.h"49#include "graph.h"5051/* Imported functions for FUNCTION POINTERS */5253extern int _CreateFwdArcLists(graphP);54extern void _CreateDFSTreeEmbedding(graphP theGraph);55extern int _SortVertices(graphP theGraph);56extern void _EmbedBackEdgeToDescendant(graphP theGraph, int RootSide, int RootVertex, int W, int WPrevLink);57extern void _WalkUp(graphP theGraph, int I, int J);58extern int _WalkDown(graphP theGraph, int I, int RootVertex);59extern int _MergeBicomps(graphP theGraph, int I, int RootVertex, int W, int WPrevLink);60extern int _HandleBlockedDescendantBicomp(graphP theGraph, int I, int RootVertex, int R, int *pRout, int *pW, int *pWPrevLink);61extern int _HandleInactiveVertex(graphP theGraph, int BicompRoot, int *pW, int *pWPrevLink);62extern int _MarkDFSPath(graphP theGraph, int ancestor, int descendant);63extern int _HandleBlockedEmbedIteration(graphP theGraph, int I);64extern int _EmbedPostprocess(graphP theGraph, int I, int edgeEmbeddingResult);65extern int _CheckEmbeddingIntegrity(graphP theGraph, graphP origGraph);66extern int _CheckObstructionIntegrity(graphP theGraph, graphP origGraph);67extern int _ReadPostprocess(graphP theGraph, void *extraData, long extraDataSize);68extern int _WritePostprocess(graphP theGraph, void **pExtraData, long *pExtraDataSize);6970/* Internal util functions for FUNCTION POINTERS */7172int _HideVertex(graphP theGraph, int vertex);73void _HideEdge(graphP theGraph, int arcPos);74void _RestoreEdge(graphP theGraph, int arcPos);75int _ContractEdge(graphP theGraph, int e);76int _IdentifyVertices(graphP theGraph, int u, int v, int eBefore);77int _RestoreVertex(graphP theGraph);7879/********************************************************************80Private functions, except exported within library81********************************************************************/8283void _ClearIsolatorContext(graphP theGraph);84void _FillVisitedFlags(graphP theGraph, int FillValue);85int _FillVisitedFlagsInBicomp(graphP theGraph, int BicompRoot, int FillValue);86int _FillVisitedFlagsInOtherBicomps(graphP theGraph, int BicompRoot, int FillValue);87void _FillVisitedFlagsInUnembeddedEdges(graphP theGraph, int FillValue);88int _SetVertexTypeInBicomp(graphP theGraph, int BicompRoot, int theType);8990int _HideInternalEdges(graphP theGraph, int vertex);91int _RestoreInternalEdges(graphP theGraph, int stackBottom);92int _RestoreHiddenEdges(graphP theGraph, int stackBottom);9394int _GetBicompSize(graphP theGraph, int BicompRoot);95int _DeleteUnmarkedEdgesInBicomp(graphP theGraph, int BicompRoot);96int _ClearInvertedFlagsInBicomp(graphP theGraph, int BicompRoot);9798void _InitFunctionTable(graphP theGraph);99100/********************************************************************101Private functions.102********************************************************************/103104void _ClearGraph(graphP theGraph);105106int _GetRandomNumber(int NMin, int NMax);107108/* Private functions for which there are FUNCTION POINTERS */109110void _InitGraphNode(graphP theGraph, int I);111void _InitVertexRec(graphP theGraph, int I);112113int _InitGraph(graphP theGraph, int N);114void _ReinitializeGraph(graphP theGraph);115int _EnsureArcCapacity(graphP theGraph, int requiredArcCapacity);116117/********************************************************************118gp_New()119Constructor for graph object.120Can create two graphs if restricted to no dynamic memory.121********************************************************************/122123graphP gp_New()124{125graphP theGraph = (graphP) malloc(sizeof(baseGraphStructure));126127if (theGraph != NULL)128{129theGraph->G = NULL;130theGraph->V = NULL;131132theGraph->BicompLists = NULL;133theGraph->DFSChildLists = NULL;134theGraph->theStack = NULL;135136theGraph->buckets = NULL;137theGraph->bin = NULL;138139theGraph->extFace = NULL;140141theGraph->edgeHoles = NULL;142143theGraph->extensions = NULL;144145_InitFunctionTable(theGraph);146147_ClearGraph(theGraph);148}149150return theGraph;151}152153/********************************************************************154_InitFunctionTable()155156If you add functions to the function table, then they must be157initialized here, but you must also add the new function pointer158to the definition of the graphFunctionTable in graphFunctionTable.h159160Function headers for the functions used to initialize the table are161classified at the top of this file as either imported from other162compilation units (extern) or private to this compilation unit.163Search for FUNCTION POINTERS in this file to see where to add the164function header.165********************************************************************/166167void _InitFunctionTable(graphP theGraph)168{169theGraph->functions.fpCreateFwdArcLists = _CreateFwdArcLists;170theGraph->functions.fpCreateDFSTreeEmbedding = _CreateDFSTreeEmbedding;171theGraph->functions.fpEmbedBackEdgeToDescendant = _EmbedBackEdgeToDescendant;172theGraph->functions.fpWalkUp = _WalkUp;173theGraph->functions.fpWalkDown = _WalkDown;174theGraph->functions.fpMergeBicomps = _MergeBicomps;175theGraph->functions.fpHandleBlockedDescendantBicomp = _HandleBlockedDescendantBicomp;176theGraph->functions.fpHandleInactiveVertex = _HandleInactiveVertex;177theGraph->functions.fpHandleBlockedEmbedIteration = _HandleBlockedEmbedIteration;178theGraph->functions.fpEmbedPostprocess = _EmbedPostprocess;179theGraph->functions.fpMarkDFSPath = _MarkDFSPath;180theGraph->functions.fpCheckEmbeddingIntegrity = _CheckEmbeddingIntegrity;181theGraph->functions.fpCheckObstructionIntegrity = _CheckObstructionIntegrity;182183theGraph->functions.fpInitGraphNode = _InitGraphNode;184theGraph->functions.fpInitVertexRec = _InitVertexRec;185186theGraph->functions.fpInitGraph = _InitGraph;187theGraph->functions.fpReinitializeGraph = _ReinitializeGraph;188theGraph->functions.fpEnsureArcCapacity = _EnsureArcCapacity;189theGraph->functions.fpSortVertices = _SortVertices;190191theGraph->functions.fpReadPostprocess = _ReadPostprocess;192theGraph->functions.fpWritePostprocess = _WritePostprocess;193194theGraph->functions.fpHideVertex = _HideVertex;195theGraph->functions.fpHideEdge = _HideEdge;196theGraph->functions.fpRestoreEdge = _RestoreEdge;197theGraph->functions.fpContractEdge = _ContractEdge;198theGraph->functions.fpIdentifyVertices = _IdentifyVertices;199theGraph->functions.fpRestoreVertex = _RestoreVertex;200}201202/********************************************************************203gp_InitGraph()204Allocates memory for vertex and edge records now that N is known.205The arcCapacity is set to (2 * DEFAULT_EDGE_LIMIT * N) unless it206has already been set by gp_EnsureArcCapacity()207208For G, we need N vertex nodes, N more vertex nodes for root copies,209and arcCapacity edge records.210211For V, we need N vertex records.212213The BicompLists and DFSChildLists are of size N and start out empty.214215The stack, initially empty, is made big enough for a pair of integers216per edge record, or 2 * arcCapacity.217218The edgeHoles stack, initially empty, is set to arcCapacity / 2,219which is big enough to push every edge (to indicate an edge220you only need to indicate one of its two edge records)221222buckets and bin are both O(N) in size. They are used by223CreateSortedSeparatedDFSChildLists()224225Returns OK on success, NOTOK on all failures.226On NOTOK, graph extensions are freed so that the graph is227returned to the post-condition of gp_New().228********************************************************************/229230int gp_InitGraph(graphP theGraph, int N)231{232// valid params check233if (theGraph == NULL || N <= 0)234return NOTOK;235236// Should not call init a second time; use reinit237if (theGraph->N > 0)238return NOTOK;239240return theGraph->functions.fpInitGraph(theGraph, N);241}242243int _InitGraph(graphP theGraph, int N)244{245int I, edgeOffset, arcCapacity, Gsize, Vsize, stackSize;246247/* Compute the vertex and edge capacities of the graph */248249Vsize = 2*N;250edgeOffset = Vsize;251arcCapacity = theGraph->arcCapacity > 0 ? theGraph->arcCapacity : 2*DEFAULT_EDGE_LIMIT*N;252Gsize = edgeOffset + arcCapacity;253stackSize = 2 * arcCapacity;254stackSize = stackSize < 6*N ? 6*N : stackSize;255256/* Allocate memory as described above */257258if ((theGraph->G = (graphNodeP) malloc(Gsize*sizeof(graphNode))) == NULL ||259(theGraph->V = (vertexRecP) malloc(N*sizeof(vertexRec))) == NULL ||260(theGraph->BicompLists = LCNew(N)) == NULL ||261(theGraph->DFSChildLists = LCNew(N)) == NULL ||262(theGraph->theStack = sp_New(stackSize)) == NULL ||263(theGraph->buckets = (int *) malloc(N * sizeof(int))) == NULL ||264(theGraph->bin = LCNew(N)) == NULL ||265(theGraph->extFace = (extFaceLinkRecP) malloc(Vsize*sizeof(extFaceLinkRec))) == NULL ||266(theGraph->edgeHoles = sp_New(arcCapacity / 2)) == NULL ||2670)268{269_ClearGraph(theGraph);270return NOTOK;271}272273/* Initialize memory */274275theGraph->N = N;276theGraph->edgeOffset = edgeOffset;277theGraph->arcCapacity = Gsize - edgeOffset;278279for (I = 0; I < Gsize; I++)280theGraph->functions.fpInitGraphNode(theGraph, I);281282for (I = 0; I < N; I++)283theGraph->functions.fpInitVertexRec(theGraph, I);284285for (I = 0; I < Vsize; I++)286{287theGraph->extFace[I].vertex[0] = theGraph->extFace[I].vertex[1] = NIL;288theGraph->extFace[I].inversionFlag = 0;289}290291_ClearIsolatorContext(theGraph);292293return OK;294}295296/********************************************************************297gp_ReinitializeGraph()298Reinitializes a graph, restoring it to the state it was in immediately299after gp_InitGraph() processed it.300********************************************************************/301302void gp_ReinitializeGraph(graphP theGraph)303{304if (theGraph == NULL || theGraph->N <= 0)305return;306307theGraph->functions.fpReinitializeGraph(theGraph);308}309310void _ReinitializeGraph(graphP theGraph)311{312int I, N = theGraph->N, edgeOffset = theGraph->edgeOffset;313int Vsize = 2*N, Gsize = edgeOffset + theGraph->arcCapacity;314315theGraph->M = 0;316theGraph->internalFlags = theGraph->embedFlags = 0;317318for (I = 0; I < Gsize; I++)319theGraph->functions.fpInitGraphNode(theGraph, I);320321for (I = 0; I < N; I++)322theGraph->functions.fpInitVertexRec(theGraph, I);323324for (I = 0; I < Vsize; I++)325{326theGraph->extFace[I].vertex[0] = theGraph->extFace[I].vertex[1] = NIL;327theGraph->extFace[I].inversionFlag = 0;328}329330_ClearIsolatorContext(theGraph);331332LCReset(theGraph->BicompLists);333LCReset(theGraph->DFSChildLists);334sp_ClearStack(theGraph->theStack);335LCReset(theGraph->bin);336sp_ClearStack(theGraph->edgeHoles);337}338339/********************************************************************340gp_GetArcCapacity()341Returns the arcCapacity of theGraph, which is twice the maximum342number of edges that can be added to the theGraph.343********************************************************************/344int gp_GetArcCapacity(graphP theGraph)345{346return theGraph->arcCapacity;347}348349/********************************************************************350gp_EnsureArcCapacity()351This method ensures that theGraph is or will be capable of storing352at least requiredArcCapacity edge records. Two edge records are353needed per edge.354355This method is most performant when invoked immediately after356gp_New(), since it must only set the arcCapacity and then let357normal initialization to occur through gp_InitGraph().358359This method is also a constant time operation if the graph already360has at least the requiredArcCapacity, since it will return OK361without making any structural changes.362363This method is generally more performant if it is invoked before364attaching extensions to the graph. Some extensions associate365parallel data with edge records, which is a faster operation if366the associated data is created and initialized only after the367proper arcCapacity is specified.368369If the graph has been initialized and has a lower arc capacity,370then the array of edge records is reallocated to satisfy the371requiredArcCapacity. The new array contains the old edges and372edge holes at the same locations, and all newly created edge records373are initialized.374375Also, if the arc capacity must be increased, then the376arcCapacity member of theGraph is changed and both377theStack and edgeHoles are expanded (since the sizes of both378are based on the arc capacity).379380Extensions that add to data associated with edges must overload381this method to ensure capacity in the parallel extension data382structures. An extension can return NOTOK if it does not383support arc capacity expansion. The extension function will384not be called if arcCapacity is expanded before the graph is385initialized, and it is assumed that extensions will allocate386parallel data structures according to the arc capacity.387388If an extension supports arc capacity expansion, then higher389performance can be obtained by using the method of unhooking390the initializers for individual edge records before invoking391the superclass version of fpEnsureArcCapacity(). Ideally,392application authors should ensure the proper arc capacity before393attaching extensions to achieve better performance.394395Returns NOTOK on failure to reallocate the edge record array to396satisfy the requiredArcCapacity, or if the requested397capacity is odd398OK if reallocation is not required or if reallocation succeeds399********************************************************************/400int gp_EnsureArcCapacity(graphP theGraph, int requiredArcCapacity)401{402if (theGraph == NULL || requiredArcCapacity <= 0)403return NOTOK;404405// Train callers to only ask for an even number of arcs, since406// two are required per edge or directed edge.407if (requiredArcCapacity & 1)408return NOTOK;409410if (theGraph->arcCapacity >= requiredArcCapacity)411return OK;412413// In the special case where gp_InitGraph() has not yet been called,414// we can simply set the higher arcCapacity since normal initialization415// will then allocate the correct number of edge records.416if (theGraph->N == 0)417{418theGraph->arcCapacity = requiredArcCapacity;419return OK;420}421422// Try to expand the arc capacity423return theGraph->functions.fpEnsureArcCapacity(theGraph, requiredArcCapacity);424}425426int _EnsureArcCapacity(graphP theGraph, int requiredArcCapacity)427{428stackP newStack;429int J, Gsize=theGraph->edgeOffset + theGraph->arcCapacity;430int newGsize = theGraph->edgeOffset + requiredArcCapacity;431432// Expand theStack433if (sp_GetCapacity(theGraph->theStack) < 2 * requiredArcCapacity)434{435int stackSize = 2 * requiredArcCapacity;436437if (stackSize < 6*theGraph->N)438{439// NOTE: Since this routine only makes the stack bigger, this440// calculation is not needed here because we already ensured441// we had stack capacity of the greater of 2*arcs and 6*N442// But we do it for clarity and consistency (e.g. so this rule443// is not forgotten whenever a "SetArcCapacity" method is added)444stackSize = 6*theGraph->N;445}446447if ((newStack = sp_New(stackSize)) == NULL)448return NOTOK;449450sp_CopyContent(newStack, theGraph->theStack);451sp_Free(&theGraph->theStack);452theGraph->theStack = newStack;453}454455// Expand edgeHoles456if ((newStack = sp_New(requiredArcCapacity / 2)) == NULL)457return NOTOK;458459sp_CopyContent(newStack, theGraph->edgeHoles);460sp_Free(&theGraph->edgeHoles);461theGraph->edgeHoles = newStack;462463// Reallocate the GraphNode array to the new size,464theGraph->G = (graphNodeP) realloc(theGraph->G, newGsize*sizeof(graphNode));465if (theGraph->G == NULL)466return NOTOK;467468// Initialize the new edge records469for (J = Gsize; J < newGsize; J++)470theGraph->functions.fpInitGraphNode(theGraph, J);471472// The new arcCapacity has been successfully achieved473theGraph->arcCapacity = requiredArcCapacity;474return OK;475}476477/********************************************************************478_InitGraphNode()479Sets the fields in a single graph node structure to initial values480********************************************************************/481482void _InitGraphNode(graphP theGraph, int J)483{484theGraph->G[J].v = NIL;485gp_SetPrevArc(theGraph, J, NIL);486gp_SetNextArc(theGraph, J, NIL);487theGraph->G[J].visited = 0;488theGraph->G[J].type = TYPE_UNKNOWN;489theGraph->G[J].flags = 0;490}491492/********************************************************************493_InitVertexRec()494Sets the fields in a single vertex record to initial values495********************************************************************/496497void _InitVertexRec(graphP theGraph, int I)498{499gp_SetFirstArc(theGraph, I, gp_AdjacencyListEndMark(I));500gp_SetLastArc(theGraph, I, gp_AdjacencyListEndMark(I));501theGraph->V[I].leastAncestor =502theGraph->V[I].Lowpoint = I;503theGraph->V[I].DFSParent = NIL;504theGraph->V[I].adjacentTo = NIL;505theGraph->V[I].pertinentBicompList = NIL;506theGraph->V[I].separatedDFSChildList = NIL;507theGraph->V[I].fwdArcList = NIL;508}509510/********************************************************************511_ClearIsolatorContext()512********************************************************************/513514void _ClearIsolatorContext(graphP theGraph)515{516isolatorContextP IC = &theGraph->IC;517518IC->minorType = 0;519IC->v = IC->r = IC->x = IC->y = IC->w = IC->px = IC->py = IC->z =520IC->ux = IC->dx = IC->uy = IC->dy = IC->dw = IC->uz = IC->dz = NIL;521}522523/********************************************************************524_FillVisitedFlags()525********************************************************************/526527void _FillVisitedFlags(graphP theGraph, int FillValue)528{529int i;530int limit = theGraph->edgeOffset + 2*(theGraph->M + sp_GetCurrentSize(theGraph->edgeHoles));531532for (i=0; i < limit; i++)533theGraph->G[i].visited = FillValue;534}535536/********************************************************************537_FillVisitedFlagsInBicomp()538539Places the FillValue into the 'visited' members of the vertices and540arcs in the bicomp rooted by BicompRoot.541542This method uses the stack but preserves whatever may have been543on it. In debug mode, it will return NOTOK if the stack overflows.544This method pushes at most one integer per vertex in the bicomp.545546Returns OK on success, NOTOK on implementation failure.547********************************************************************/548549int _FillVisitedFlagsInBicomp(graphP theGraph, int BicompRoot, int FillValue)550{551int V, J;552int stackBottom = sp_GetCurrentSize(theGraph->theStack);553554sp_Push(theGraph->theStack, BicompRoot);555while (sp_GetCurrentSize(theGraph->theStack) > stackBottom)556{557sp_Pop(theGraph->theStack, V);558theGraph->G[V].visited = FillValue;559560J = gp_GetFirstArc(theGraph, V);561while (gp_IsArc(theGraph, J))562{563theGraph->G[J].visited = FillValue;564565if (theGraph->G[J].type == EDGE_DFSCHILD)566sp_Push(theGraph->theStack, theGraph->G[J].v);567568J = gp_GetNextArc(theGraph, J);569}570}571return OK;572}573574/********************************************************************575_FillVisitedFlagsInOtherBicomps()576Typically, we want to clear or set all visited flags in the graph577(see _FillVisitedFlags). However, in some algorithms this would be578too costly, so it is necessary to clear or set the visited flags only579in one bicomp (see _FillVisitedFlagsInBicomp), then do some processing580that sets some of the flags then performs some tests. If the tests581are positive, then we can clear or set all the visited flags in the582other bicomps (the processing may have set the visited flags in the583one bicomp in a particular way that we want to retain, so we skip584the given bicomp).585********************************************************************/586587int _FillVisitedFlagsInOtherBicomps(graphP theGraph, int BicompRoot, int FillValue)588{589int R, edgeOffset = theGraph->edgeOffset;590591for (R = theGraph->N; R < edgeOffset; R++)592{593if (R != BicompRoot && gp_IsArc(theGraph, gp_GetFirstArc(theGraph, R)) )594{595if (_FillVisitedFlagsInBicomp(theGraph, R, FillValue) != OK)596return NOTOK;597}598}599return OK;600}601602/********************************************************************603_FillVisitedFlagsInUnembeddedEdges()604Unembedded edges aren't part of any bicomp yet, but it may be605necessary to fill their visited flags, typically with zero.606********************************************************************/607608void _FillVisitedFlagsInUnembeddedEdges(graphP theGraph, int FillValue)609{610int I, J;611612for (I = 0; I < theGraph->N; I++)613{614J = theGraph->V[I].fwdArcList;615while (gp_IsArc(theGraph, J))616{617theGraph->G[J].visited =618theGraph->G[gp_GetTwinArc(theGraph, J)].visited = FillValue;619620J = gp_GetNextArc(theGraph, J);621if (J == theGraph->V[I].fwdArcList)622J = NIL;623}624}625}626627/********************************************************************628_SetVertexTypeInBicomp()629630Sets the 'type' member to theType for each vertex in the bicomp631rooted by BicompRoot.632633This method uses the stack but preserves whatever may have been634on it. In debug mode, it will return NOTOK if the stack overflows.635This method pushes at most one integer per vertex in the bicomp.636637Returns OK on success, NOTOK on implementation failure.638********************************************************************/639640int _SetVertexTypeInBicomp(graphP theGraph, int BicompRoot, int theType)641{642int V, J;643int stackBottom = sp_GetCurrentSize(theGraph->theStack);644645sp_Push(theGraph->theStack, BicompRoot);646while (sp_GetCurrentSize(theGraph->theStack) > stackBottom)647{648sp_Pop(theGraph->theStack, V);649theGraph->G[V].type = theType;650651J = gp_GetFirstArc(theGraph, V);652while (gp_IsArc(theGraph, J))653{654if (theGraph->G[J].type == EDGE_DFSCHILD)655sp_Push(theGraph->theStack, theGraph->G[J].v);656657J = gp_GetNextArc(theGraph, J);658}659}660return OK;661}662663/********************************************************************664_ClearGraph()665Clears all memory used by the graph, restoring it to the state it666was in immediately after gp_New() created it.667********************************************************************/668669void _ClearGraph(graphP theGraph)670{671if (theGraph->G != NULL)672{673free(theGraph->G);674theGraph->G = NULL;675}676if (theGraph->V != NULL)677{678free(theGraph->V);679theGraph->V = NULL;680}681682theGraph->N = theGraph->M = theGraph->edgeOffset = theGraph->arcCapacity = 0;683theGraph->internalFlags = theGraph->embedFlags = 0;684685_ClearIsolatorContext(theGraph);686687LCFree(&theGraph->BicompLists);688LCFree(&theGraph->DFSChildLists);689690sp_Free(&theGraph->theStack);691692if (theGraph->buckets != NULL)693{694free(theGraph->buckets);695theGraph->buckets = NULL;696}697698LCFree(&theGraph->bin);699700if (theGraph->extFace != NULL)701{702free(theGraph->extFace);703theGraph->extFace = NULL;704}705706sp_Free(&theGraph->edgeHoles);707708gp_FreeExtensions(theGraph);709}710711/********************************************************************712gp_Free()713Frees G and V, then the graph record. Then sets your pointer to NULL714(so you must pass the address of your pointer).715********************************************************************/716717void gp_Free(graphP *pGraph)718{719if (pGraph == NULL) return;720if (*pGraph == NULL) return;721722_ClearGraph(*pGraph);723724free(*pGraph);725*pGraph = NULL;726}727728/********************************************************************729gp_CopyGraph()730Copies the content of the srcGraph into the dstGraph. The dstGraph731must have been previously initialized with the same number of732vertices as the srcGraph (e.g. gp_InitGraph(dstGraph, srcGraph->N).733734Returns OK for success, NOTOK for failure.735********************************************************************/736737int gp_CopyGraph(graphP dstGraph, graphP srcGraph)738{739int I, N = srcGraph->N, edgeOffset = srcGraph->edgeOffset;740int Gsize = edgeOffset + srcGraph->arcCapacity;741742// Parameter checks743if (dstGraph == NULL || srcGraph == NULL)744{745return NOTOK;746}747748// The graphs need to be the same order and initialized749if (dstGraph->N != srcGraph->N || dstGraph->N == 0)750{751return NOTOK;752}753754// Ensure dstGraph has the required arc capacity; this expands755// dstGraph if needed, but does not contract. An error is only756// returned if the expansion fails.757if (gp_EnsureArcCapacity(dstGraph, srcGraph->arcCapacity) != OK)758{759return NOTOK;760}761762// Copy the basic GraphNode structures. Augmentations to763// the graph node structure created by extensions are copied764// below by gp_CopyExtensions()765for (I = 0; I < Gsize; I++)766dstGraph->G[I] = srcGraph->G[I];767768// Copy the basic VertexRec structures. Augmentations to769// the vertex structure created by extensions are copied770// below by gp_CopyExtensions()771for (I = 0; I < N; I++)772dstGraph->V[I] = srcGraph->V[I];773774// Copy the external face array775for (I = 0; I < edgeOffset; I++)776{777dstGraph->extFace[I].vertex[0] = srcGraph->extFace[I].vertex[0];778dstGraph->extFace[I].vertex[1] = srcGraph->extFace[I].vertex[1];779dstGraph->extFace[I].inversionFlag = srcGraph->extFace[I].inversionFlag;780}781782// Give the dstGraph the same size and intrinsic properties783dstGraph->N = srcGraph->N;784dstGraph->M = srcGraph->M;785dstGraph->edgeOffset = srcGraph->edgeOffset;786dstGraph->internalFlags = srcGraph->internalFlags;787dstGraph->embedFlags = srcGraph->embedFlags;788789dstGraph->IC = srcGraph->IC;790791LCCopy(dstGraph->BicompLists, srcGraph->BicompLists);792LCCopy(dstGraph->DFSChildLists, srcGraph->DFSChildLists);793sp_Copy(dstGraph->theStack, srcGraph->theStack);794sp_Copy(dstGraph->edgeHoles, srcGraph->edgeHoles);795796// Copy the set of extensions, which includes copying the797// extension data as well as the function overload tables798if (gp_CopyExtensions(dstGraph, srcGraph) != OK)799return NOTOK;800801// Copy the graph's function table, which has the pointers to802// the most recent extension overloads of each function (or803// the original function pointer if a particular function has804// not been overloaded).805// This must be done after copying the extension because the806// first step of copying the extensions is to delete the807// dstGraph extensions, which clears its function table.808// Therefore, no good to assign the srcGraph functions *before*809// copying the extensions because the assignment would be wiped out810// This, in turn, means that the DupContext function of an extension811// *cannot* depend on any extension function overloads; the extension812// must directly invoke extension functions only.813dstGraph->functions = srcGraph->functions;814815return OK;816}817818/********************************************************************819gp_DupGraph()820********************************************************************/821822graphP gp_DupGraph(graphP theGraph)823{824graphP result;825826if ((result = gp_New()) == NULL) return NULL;827828if (gp_InitGraph(result, theGraph->N) != OK ||829gp_CopyGraph(result, theGraph) != OK)830{831gp_Free(&result);832return NULL;833}834835return result;836}837838/********************************************************************839gp_CreateRandomGraph()840841Creates a randomly generated graph. First a tree is created by842connecting each vertex to some successor. Then a random number of843additional random edges are added. If an edge already exists, then844we retry until a non-existent edge is picked.845846This function assumes the caller has already called srand().847848Returns OK on success, NOTOK on failure849********************************************************************/850851int gp_CreateRandomGraph(graphP theGraph)852{853int N, I, M, u, v;854855N = theGraph->N;856857/* Generate a random tree; note that this method virtually guarantees858that the graph will be renumbered, but it is linear time.859Also, we are not generating the DFS tree but rather a tree860that simply ensures the resulting random graph is connected. */861862for (I=1; I < N; I++)863if (gp_AddEdge(theGraph, _GetRandomNumber(0, I-1), 0, I, 0) != OK)864return NOTOK;865866/* Generate a random number of additional edges867(actually, leave open a small chance that no868additional edges will be added). */869870M = _GetRandomNumber(7*N/8, theGraph->arcCapacity/2);871872if (M > N*(N-1)/2) M = N*(N-1)/2;873874for (I=N-1; I<M; I++)875{876u = _GetRandomNumber(0, N-2);877v = _GetRandomNumber(u+1, N-1);878879if (gp_IsNeighbor(theGraph, u, v))880I--;881else882{883if (gp_AddEdge(theGraph, u, 0, v, 0) != OK)884return NOTOK;885}886}887888return OK;889}890891/********************************************************************892_GetRandomNumber()893This function generates a random number between NMin and NMax894inclusive. It assumes that the caller has called srand().895It calls rand(), but before truncating to the proper range,896it adds the high bits of the rand() result into the low bits.897The result of this is that the randomness appearing in the898truncated bits also has an affect on the non-truncated bits.899I used the same technique to improve the spread of hashing functions900in my Jan.98 Dr. Dobb's Journal article "Resizable Data Structures".901********************************************************************/902903int _GetRandomNumber(int NMin, int NMax)904{905int N = rand();906907if (NMax < NMin) return NMin;908909N += ((N&0xFFFF0000)>>16);910N += ((N&0x0000FF00)>>8);911N &= 0x7FFFFFF;912N %= (NMax-NMin+1);913return N+NMin;914}915916/********************************************************************917_getUnprocessedChild()918Support routine for gp_Create RandomGraphEx(), this function919obtains a child of the given vertex in the randomly generated920tree that has not yet been processed. NIL is returned if the921given vertex has no unprocessed children922923********************************************************************/924925int _getUnprocessedChild(graphP theGraph, int parent)926{927int J = gp_GetFirstArc(theGraph, parent);928int JTwin = gp_GetTwinArc(theGraph, J);929int child = theGraph->G[J].v;930931// The tree edges were added to the beginning of the adjacency list,932// and we move processed tree edge records to the end of the list,933// so if the immediate next arc (edge record) is not a tree edge934// then we return NIL because the vertex has no remaining935// unprocessed children936if (theGraph->G[J].type == TYPE_UNKNOWN)937return NIL;938939// If the child has already been processed, then all children940// have been pushed to the end of the list, and we have just941// encountered the first child we processed, so there are no942// remaining unprocessed children */943if (theGraph->G[J].visited)944return NIL;945946// We have found an edge leading to an unprocessed child, so947// we mark it as processed so that it doesn't get returned948// again in future iterations.949theGraph->G[J].visited = 1;950theGraph->G[JTwin].visited = 1;951952// Now we move the edge record in the parent vertex to the end953// of the adjacency list of that vertex.954gp_MoveArcToLast(theGraph, parent, J);955956// Now we move the edge record in the child vertex to the957// end of the adjacency list of the child.958gp_MoveArcToLast(theGraph, child, JTwin);959960// Now we set the child's parent and return the child.961theGraph->V[child].DFSParent = parent;962963return child;964}965966/********************************************************************967_hasUnprocessedChild()968Support routine for gp_Create RandomGraphEx(), this function969obtains a child of the given vertex in the randomly generated970tree that has not yet been processed. False (0) is returned971unless the given vertex has an unprocessed child.972********************************************************************/973974int _hasUnprocessedChild(graphP theGraph, int parent)975{976int J = gp_GetFirstArc(theGraph, parent);977978if (theGraph->G[J].type == TYPE_UNKNOWN)979return 0;980981if (theGraph->G[J].visited)982return 0;983984return 1;985}986987/********************************************************************988gp_CreateRandomGraphEx()989Given a graph structure with a pre-specified number of vertices N,990this function creates a graph with the specified number of edges.991992If numEdges <= 3N-6, then the graph generated is planar. If993numEdges is larger, then a maximal planar graph is generated, then994(numEdges - 3N + 6) additional random edges are added.995996This function assumes the caller has already called srand().997********************************************************************/998999int gp_CreateRandomGraphEx(graphP theGraph, int numEdges)1000{1001#define EDGE_TREE_RANDOMGEN (TYPE_UNKNOWN+1)10021003int N, I, arc, M, root, v, c, p, last, u, J, e;10041005N = theGraph->N;10061007if (numEdges > theGraph->arcCapacity/2)1008numEdges = theGraph->arcCapacity/2;10091010/* Generate a random tree. */10111012for (I=1; I < N; I++)1013{1014v = _GetRandomNumber(0, I-1);1015if (gp_AddEdge(theGraph, v, 0, I, 0) != OK)1016return NOTOK;10171018else1019{1020arc = theGraph->edgeOffset + 2*theGraph->M - 2;1021theGraph->G[arc].type = EDGE_TREE_RANDOMGEN;1022theGraph->G[gp_GetTwinArc(theGraph, arc)].type = EDGE_TREE_RANDOMGEN;1023theGraph->G[arc].visited = 0;1024theGraph->G[gp_GetTwinArc(theGraph, arc)].visited = 0;1025}1026}10271028/* Add edges up to the limit or until the graph is maximal planar. */10291030M = numEdges <= 3*N - 6 ? numEdges : 3*N - 6;10311032root = 0;1033v = last = _getUnprocessedChild(theGraph, root);10341035while (v != root && theGraph->M < M)1036{1037c = _getUnprocessedChild(theGraph, v);10381039if (c != NIL)1040{1041if (last != v)1042{1043if (gp_AddEdge(theGraph, last, 1, c, 1) != OK)1044return NOTOK;1045}10461047if (gp_AddEdge(theGraph, root, 1, c, 1) != OK)1048return NOTOK;10491050v = last = c;1051}10521053else1054{1055p = theGraph->V[v].DFSParent;1056while (p != NIL && (c = _getUnprocessedChild(theGraph, p)) == NIL)1057{1058v = p;1059p = theGraph->V[v].DFSParent;1060if (p != NIL && p != root)1061{1062if (gp_AddEdge(theGraph, last, 1, p, 1) != OK)1063return NOTOK;1064}1065}10661067if (p != NIL)1068{1069if (p == root)1070{1071if (gp_AddEdge(theGraph, v, 1, c, 1) != OK)1072return NOTOK;10731074if (v != last)1075{1076if (gp_AddEdge(theGraph, last, 1, c, 1) != OK)1077return NOTOK;1078}1079}1080else1081{1082if (gp_AddEdge(theGraph, last, 1, c, 1) != OK)1083return NOTOK;1084}10851086if (p != root)1087{1088if (gp_AddEdge(theGraph, root, 1, c, 1) != OK)1089return NOTOK;1090last = c;1091}10921093v = c;1094}1095}1096}10971098/* Add additional edges if the limit has not yet been reached. */10991100while (theGraph->M < numEdges)1101{1102u = _GetRandomNumber(0, N-1);1103v = _GetRandomNumber(0, N-1);11041105if (u != v && !gp_IsNeighbor(theGraph, u, v))1106if (gp_AddEdge(theGraph, u, 0, v, 0) != OK)1107return NOTOK;1108}11091110/* Clear the edge types back to 'unknown' */11111112for (e = 0; e < numEdges; e++)1113{1114J = theGraph->edgeOffset + 2*e;1115theGraph->G[J].type = TYPE_UNKNOWN;1116theGraph->G[gp_GetTwinArc(theGraph, J)].type = TYPE_UNKNOWN;1117theGraph->G[J].visited = 0;1118theGraph->G[gp_GetTwinArc(theGraph, J)].visited = 0;1119}11201121/* Put all DFSParent indicators back to NIL */11221123for (I = 0; I < N; I++)1124theGraph->V[I].DFSParent = NIL;11251126return OK;11271128#undef EDGE_TREE_RANDOMGEN1129}11301131/********************************************************************1132gp_SetDirection()1133Behavior depends on edgeFlag_Direction (EDGEFLAG_DIRECTION_INONLY,1134EDGEFLAG_DIRECTION_OUTONLY, or 0).1135A direction of 0 clears directedness. Otherwise, edge record e is set1136to edgeFlag_Direction and e's twin arc is set to the opposing setting.1137********************************************************************/11381139void gp_SetDirection(graphP theGraph, int e, int edgeFlag_Direction)1140{1141int eTwin = gp_GetTwinArc(theGraph, e);11421143if (edgeFlag_Direction == EDGEFLAG_DIRECTION_INONLY)1144{1145theGraph->G[e].flags |= EDGEFLAG_DIRECTION_INONLY;1146theGraph->G[eTwin].flags |= EDGEFLAG_DIRECTION_OUTONLY;1147}1148else if (edgeFlag_Direction == EDGEFLAG_DIRECTION_OUTONLY)1149{1150theGraph->G[e].flags |= EDGEFLAG_DIRECTION_OUTONLY;1151theGraph->G[eTwin].flags |= EDGEFLAG_DIRECTION_INONLY;1152}1153else1154{1155theGraph->G[e].flags &= ~(EDGEFLAG_DIRECTION_INONLY|EDGEFLAG_DIRECTION_OUTONLY);1156theGraph->G[eTwin].flags &= ~(EDGEFLAG_DIRECTION_INONLY|EDGEFLAG_DIRECTION_OUTONLY);1157}1158}11591160/********************************************************************1161gp_IsNeighbor()11621163Checks whether v is already in u's adjacency list, i.e. does the arc1164u -> v exist.1165If there is an edge record for v in u's list, but it is marked INONLY,1166then it represents the arc v->u but not u->v, so it is ignored.11671168Returns TRUE or FALSE.1169********************************************************************/11701171int gp_IsNeighbor(graphP theGraph, int u, int v)1172{1173int J;11741175J = gp_GetFirstArc(theGraph, u);1176while (gp_IsArc(theGraph, J))1177{1178if (theGraph->G[J].v == v)1179{1180if (!gp_GetDirection(theGraph, J, EDGEFLAG_DIRECTION_INONLY))1181return TRUE;1182}1183J = gp_GetNextArc(theGraph, J);1184}1185return FALSE;1186}11871188/********************************************************************1189gp_GetNeighborEdgeRecord()1190Searches the adjacency list of u to obtains the edge record for v.11911192NOTE: The caller should check whether the edge record is INONLY;1193This method returns any edge record representing a connection1194between vertices u and v, so this method can return an1195edge record even if gp_IsNeighbor(theGraph, u, v) is false (0).1196To filter out INONLY edge records, use gp_GetDirection() on1197the edge record returned by this method.11981199Returns NIL if there is no edge record indicating v in u's adjacency1200list, or the edge record location otherwise.1201********************************************************************/12021203int gp_GetNeighborEdgeRecord(graphP theGraph, int u, int v)1204{1205int J;12061207if (u == NIL || v == NIL)1208return NIL + NOTOK;12091210J = gp_GetFirstArc(theGraph, u);1211while (gp_IsArc(theGraph, J))1212{1213if (theGraph->G[J].v == v)1214return J;12151216J = gp_GetNextArc(theGraph, J);1217}1218return NIL;1219}12201221/********************************************************************1222gp_GetVertexDegree()12231224Counts the number of edge records in the adjacency list of a given1225vertex V. The while loop condition is 2N or higher because our1226data structure keeps records at locations 0 to N-1 for vertices1227AND N to 2N-1 for copies of vertices. So edge records are stored1228at locations 2N and above.12291230Note: For digraphs, this method returns the total degree of the1231vertex, including outward arcs (undirected and OUTONLY)1232as well as INONLY arcs. Other functions are defined to get1233the in-degree or out-degree of the vertex.12341235Note: This function determines the degree by counting. An extension1236could cache the degree value of each vertex and update the1237cached value as edges are added and deleted.1238********************************************************************/12391240int gp_GetVertexDegree(graphP theGraph, int v)1241{1242int J, degree;12431244if (theGraph==NULL || v==NIL)1245return NOTOK;12461247degree = 0;12481249J = gp_GetFirstArc(theGraph, v);1250while (gp_IsArc(theGraph, J))1251{1252degree++;1253J = gp_GetNextArc(theGraph, J);1254}12551256return degree;1257}12581259/********************************************************************1260gp_GetVertexInDegree()12611262Counts the number of edge records in the adjacency list of a given1263vertex V that represent arcs from another vertex into V.1264This includes undirected edges and INONLY arcs, so it only excludes1265edges records that are marked as OUTONLY arcs.12661267Note: This function determines the in-degree by counting. An extension1268could cache the in-degree value of each vertex and update the1269cached value as edges are added and deleted.1270********************************************************************/12711272int gp_GetVertexInDegree(graphP theGraph, int v)1273{1274int J, degree;12751276if (theGraph==NULL || v==NIL)1277return NOTOK;12781279degree = 0;12801281J = gp_GetFirstArc(theGraph, v);1282while (gp_IsArc(theGraph, J))1283{1284if (!gp_GetDirection(theGraph, J, EDGEFLAG_DIRECTION_OUTONLY))1285degree++;1286J = gp_GetNextArc(theGraph, J);1287}12881289return degree;1290}12911292/********************************************************************1293gp_GetVertexOutDegree()12941295Counts the number of edge records in the adjacency list of a given1296vertex V that represent arcs from V to another vertex.1297This includes undirected edges and OUTONLY arcs, so it only excludes1298edges records that are marked as INONLY arcs.12991300Note: This function determines the out-degree by counting. An extension1301could cache the out-degree value of each vertex and update the1302cached value as edges are added and deleted.1303********************************************************************/13041305int gp_GetVertexOutDegree(graphP theGraph, int v)1306{1307int J, degree;13081309if (theGraph==NULL || v==NIL)1310return NOTOK;13111312degree = 0;13131314J = gp_GetFirstArc(theGraph, v);1315while (gp_IsArc(theGraph, J))1316{1317if (!gp_GetDirection(theGraph, J, EDGEFLAG_DIRECTION_INONLY))1318degree++;1319J = gp_GetNextArc(theGraph, J);1320}13211322return degree;1323}13241325/********************************************************************1326gp_AttachArc()13271328This routine adds newArc into v's adjacency list at a position1329adjacent to the edge record for e, either before or after e,1330depending on link. If e is not an arc (e.g. if e is NIL),1331then link is assumed to indicate whether the new arc is to be1332placed at the beginning or end of v's adjacency list.13331334NOTE: The caller can pass NIL for v if e is not NIL, since the1335vertex is implied (theGraph->G[eTwin].v)13361337The arc is assumed to already exist in the data structure (i.e.1338the storage of edges), as only a whole edge (two arcs) can be1339inserted into or deleted from the data structure. Hence there is1340no such thing as gp_InsertArc() or gp_DeleteArc().13411342See also gp_DetachArc(), gp_InsertEdge() and gp_DeleteEdge()1343********************************************************************/13441345void gp_AttachArc(graphP theGraph, int v, int e, int link, int newArc)1346{1347if (gp_IsArc(theGraph, e))1348{1349int e2 = gp_GetAdjacentArc(theGraph, e, link);13501351// e's link is newArc, and newArc's 1^link is e1352gp_SetAdjacentArc(theGraph, e, link, newArc);1353gp_SetAdjacentArc(theGraph, newArc, 1^link, e);13541355// newArcs's link is e21356gp_SetAdjacentArc(theGraph, newArc, link, e2);13571358// if e2 is an arc, then e2's 1^link is newArc, else v's 1^link is newArc1359if (gp_IsArc(theGraph, e2))1360gp_SetAdjacentArc(theGraph, e2, 1^link, newArc);1361else1362gp_SetArc(theGraph, v, 1^link, newArc);1363}1364else1365{1366int e2 = gp_GetArc(theGraph, v, link);13671368// v's link is newArc, and newArc's 1^link is gp_AdjacencyListEndMark(v)1369gp_SetArc(theGraph, v, link, newArc);1370gp_SetAdjacentArc(theGraph, newArc, 1^link, gp_AdjacencyListEndMark(v));13711372// newArcs's elink is e21373gp_SetAdjacentArc(theGraph, newArc, link, e2);13741375// if e2 is an arc, then e2's 1^link is newArc, else v's 1^link is newArc1376if (gp_IsArc(theGraph, e2))1377gp_SetAdjacentArc(theGraph, e2, 1^link, newArc);1378else1379gp_SetArc(theGraph, v, 1^link, newArc);1380}1381}13821383/****************************************************************************1384gp_DetachArc()13851386This routine detaches arc from its adjacency list, but it does not delete1387it from the data structure (only a whole edge can be deleted).13881389Some algorithms must temporarily detach an edge, perform some calculation,1390and eventually put the edge back. This routine supports that operation.1391The neighboring adjacency list nodes are cross-linked, but the two link1392members of the arc are retained, so the arc can be reattached later by1393invoking _RestoreArc(). A sequence of detached arcs can only be restored1394in the exact opposite order of their detachment. Thus, algorithms do not1395directly use this method to implement the temporary detach/restore method.1396Instead, gp_HideEdge() and gp_RestoreEdge are used, and algorithms push1397edge hidden edge onto the stack. One example of this stack usage is1398provided by detaching edges with gp_ContractEdge() or gp_IdentifyVertices(),1399and reattaching with gp_RestoreIdentifications(), which unwinds the stack1400by invoking gp_RestoreVertex().1401****************************************************************************/14021403void gp_DetachArc(graphP theGraph, int arc)1404{1405int nextArc = gp_GetNextArc(theGraph, arc),1406prevArc = gp_GetPrevArc(theGraph, arc);14071408if (gp_IsArc(theGraph, nextArc))1409gp_SetPrevArc(theGraph, nextArc, prevArc);1410else1411gp_SetLastArc(theGraph, theGraph->G[gp_GetTwinArc(theGraph, arc)].v, prevArc);14121413if (gp_IsArc(theGraph, prevArc))1414gp_SetNextArc(theGraph, prevArc, nextArc);1415else1416gp_SetFirstArc(theGraph, theGraph->G[gp_GetTwinArc(theGraph, arc)].v, nextArc);1417}14181419/********************************************************************1420gp_AddEdge()1421Adds the undirected edge (u,v) to the graph by placing edge records1422representing u into v's circular edge record list and v into u's1423circular edge record list.14241425upos receives the location in G where the u record in v's list will be1426placed, and vpos is the location in G of the v record we placed in1427u's list. These are used to initialize the short circuit links.14281429ulink (0|1) indicates whether the edge record to v in u's list should1430become adjacent to u by its 0 or 1 link, i.e. u[ulink] == vpos.1431vlink (0|1) indicates whether the edge record to u in v's list should1432become adjacent to v by its 0 or 1 link, i.e. v[vlink] == upos.14331434********************************************************************/14351436int gp_AddEdge(graphP theGraph, int u, int ulink, int v, int vlink)1437{1438int upos, vpos;14391440if (theGraph==NULL || u<0 || v<0 ||1441u>=2*theGraph->N || v>=2*theGraph->N)1442return NOTOK;14431444/* We enforce the edge limit */14451446if (theGraph->M >= theGraph->arcCapacity/2)1447return NONEMBEDDABLE;14481449if (sp_NonEmpty(theGraph->edgeHoles))1450{1451sp_Pop(theGraph->edgeHoles, vpos);1452}1453else1454vpos = theGraph->edgeOffset + 2*theGraph->M;14551456upos = gp_GetTwinArc(theGraph, vpos);14571458theGraph->G[upos].v = v;1459gp_AttachArc(theGraph, u, NIL, ulink, upos);1460theGraph->G[vpos].v = u;1461gp_AttachArc(theGraph, v, NIL, vlink, vpos);14621463theGraph->M++;1464return OK;1465}14661467/********************************************************************1468gp_InsertEdge()14691470This function adds the edge (u, v) such that the edge record added1471to the adjacency list of u is adjacent to e_u and the edge record1472added to the adjacency list of v is adjacent to e_v.1473The direction of adjacency is given by e_ulink for e_u and e_vlink1474for e_v. Specifically, the new edge will be comprised of two arcs,1475n_u and n_v. In u's (v's) adjacency list, n_u (n_v) will be added1476so that it is indicated by e_u's (e_v's) e_ulink (e_vlink).1477If e_u (or e_v) is not an arc, then e_ulink (e_vlink) indicates1478whether to prepend or append to the adjacency list for u (v).1479********************************************************************/14801481int gp_InsertEdge(graphP theGraph, int u, int e_u, int e_ulink,1482int v, int e_v, int e_vlink)1483{1484int vertMax = 2*theGraph->N - 1,1485edgeMax = theGraph->edgeOffset + 2*theGraph->M + 2*sp_GetCurrentSize(theGraph->edgeHoles) - 1,1486upos, vpos;14871488if (theGraph==NULL || u<0 || v<0 || u>vertMax || v>vertMax ||1489e_u>edgeMax || (e_u<theGraph->edgeOffset && e_u != gp_AdjacencyListEndMark(u)) ||1490e_v>edgeMax || (e_v<theGraph->edgeOffset && e_v != gp_AdjacencyListEndMark(v)) ||1491e_ulink<0 || e_ulink>1 || e_vlink<0 || e_vlink>1)1492return NOTOK;14931494if (theGraph->M >= theGraph->arcCapacity/2)1495return NONEMBEDDABLE;14961497if (sp_NonEmpty(theGraph->edgeHoles))1498{1499sp_Pop(theGraph->edgeHoles, vpos);1500}1501else1502vpos = theGraph->edgeOffset + 2*theGraph->M;15031504upos = gp_GetTwinArc(theGraph, vpos);15051506theGraph->G[upos].v = v;1507gp_AttachArc(theGraph, u, e_u, e_ulink, upos);15081509theGraph->G[vpos].v = u;1510gp_AttachArc(theGraph, v, e_v, e_vlink, vpos);15111512theGraph->M++;15131514return OK;1515}15161517/****************************************************************************1518gp_DeleteEdge()15191520This function deletes the given edge record e and its twin, reducing the1521number of edges M in the graph.1522Before the e^th record is deleted, its 'nextLink' adjacency list neighbor1523is collected as the return result. This is useful when iterating through1524an edge list and making deletions because the nextLink arc is the 'next'1525arc in the iteration, but it is hard to obtain *after* deleting e.1526****************************************************************************/15271528int gp_DeleteEdge(graphP theGraph, int e, int nextLink)1529{1530int eTwin = gp_GetTwinArc(theGraph, e);1531int M = theGraph->M;1532int nextArc, JPos, MPos;15331534/* Calculate the nextArc after e so that, when e is deleted, the return result1535informs a calling loop of the next edge to be processed. */15361537nextArc = gp_GetAdjacentArc(theGraph, e, nextLink);15381539/* Delete the edge records J and JTwin from their adjacency lists. */15401541gp_DetachArc(theGraph, e);1542gp_DetachArc(theGraph, eTwin);15431544/* Clear the edge record contents */15451546theGraph->functions.fpInitGraphNode(theGraph, e);1547theGraph->functions.fpInitGraphNode(theGraph, eTwin);15481549/* If records e and eTwin are not the last in the edge record array, then1550we want to record a new hole in the edge array. */15511552JPos = (e < eTwin ? e : eTwin);1553MPos = theGraph->edgeOffset + 2*(M-1) + 2*sp_GetCurrentSize(theGraph->edgeHoles);15541555if (JPos < MPos)1556{1557sp_Push(theGraph->edgeHoles, JPos);1558}15591560/* Now we reduce the number of edges in the data structure, and then1561return the previously calculated successor of J. */15621563theGraph->M--;1564return nextArc;1565}15661567/********************************************************************1568_RestoreArc()1569This routine reinserts an arc into the edge list from which it1570was previously removed by gp_DetachArc().15711572The assumed processing model is that arcs will be restored in reverse1573of the order in which they were hidden, i.e. it is assumed that the1574hidden arcs will be pushed on a stack and the arcs will be popped1575from the stack for restoration.1576********************************************************************/15771578void _RestoreArc(graphP theGraph, int arc)1579{1580int nextArc = gp_GetNextArc(theGraph, arc),1581prevArc = gp_GetPrevArc(theGraph, arc);15821583if (gp_IsArc(theGraph, nextArc))1584gp_SetPrevArc(theGraph, nextArc, arc);1585else1586gp_SetLastArc(theGraph, theGraph->G[gp_GetTwinArc(theGraph, arc)].v, arc);15871588if (gp_IsArc(theGraph, prevArc))1589gp_SetNextArc(theGraph, prevArc, arc);1590else1591gp_SetFirstArc(theGraph, theGraph->G[gp_GetTwinArc(theGraph, arc)].v, arc);1592}15931594/********************************************************************1595gp_HideEdge()1596This routine removes the two arcs of an edge from the adjacency lists1597of its endpoint vertices, but does not delete them from the storage1598data structure.15991600Many algorithms must temporarily remove an edge, perform some1601calculation, and eventually put the edge back. This routine supports1602that operation.16031604For each arc, the neighboring adjacency list nodes are cross-linked,1605but the links in the arc are retained because they indicate the1606neighbor arcs to which the arc can be reattached by gp_RestoreEdge().1607********************************************************************/16081609void gp_HideEdge(graphP theGraph, int e)1610{1611theGraph->functions.fpHideEdge(theGraph, e);1612}16131614void _HideEdge(graphP theGraph, int e)1615{1616gp_DetachArc(theGraph, e);1617gp_DetachArc(theGraph, gp_GetTwinArc(theGraph, e));1618}16191620/********************************************************************1621gp_RestoreEdge()1622This routine reinserts two two arcs of an edge into the adjacency1623lists of the edge's endpoints, the arcs having been previously1624removed by gp_HideEdge().16251626The assumed processing model is that edges will be restored in1627reverse of the order in which they were hidden, i.e. it is assumed1628that the hidden edges will be pushed on a stack and the edges will1629be popped from the stack for restoration.16301631Note: Since both arcs of an edge are restored, only one arc need1632be pushed on the stack for restoration. This routine1633restores the two arcs in the opposite order from the order1634in which they are hidden by gp_HideEdge().1635********************************************************************/16361637void gp_RestoreEdge(graphP theGraph, int e)1638{1639theGraph->functions.fpRestoreEdge(theGraph, e);1640}16411642void _RestoreEdge(graphP theGraph, int e)1643{1644_RestoreArc(theGraph, gp_GetTwinArc(theGraph, e));1645_RestoreArc(theGraph, e);1646}16471648/********************************************************************1649_HideInternalEdges()1650Pushes onto the graph's stack and hides all arc nodes of the vertex1651except the first and last arcs in the adjacency list of the vertex.1652This method is typically called on a vertex that is on the external1653face of a biconnected component, because the first and last arcs are1654the ones that attach the vertex to the external face cycle, and any1655other arcs in the adjacency list are inside that cycle.16561657This method uses the stack. The caller is expected to clear the stack1658or save the stack size before invocation, since the stack size is1659needed to _RestoreInternalEdges().1660********************************************************************/16611662int _HideInternalEdges(graphP theGraph, int vertex)1663{1664int J = gp_GetFirstArc(theGraph, vertex);16651666// If the vertex adjacency list is empty or if it contains1667// only one edge, then there are no *internal* edges to hide1668if (J == gp_GetLastArc(theGraph, vertex))1669return OK;16701671// Start with the first internal edge1672J = gp_GetNextArc(theGraph, J);16731674// Cycle through all the edges, pushing each except stop1675// before pushing the last edge, which is not internal1676while (J != gp_GetLastArc(theGraph, vertex))1677{1678sp_Push(theGraph->theStack, J);1679gp_HideEdge(theGraph, J);1680J = gp_GetNextArc(theGraph, J);1681}16821683return OK;1684}16851686/********************************************************************1687_RestoreInternalEdges()1688Reverses the effects of _HideInternalEdges()1689********************************************************************/16901691int _RestoreInternalEdges(graphP theGraph, int stackBottom)1692{1693return _RestoreHiddenEdges(theGraph, stackBottom);1694}16951696/********************************************************************1697_RestoreHiddenEdges()16981699Each entry on the stack, down to stackBottom, is assumed to be an1700edge record (arc) pushed in concert with invoking gp_HideEdge().1701Each edge is restored using gp_RestoreEdge() in exact reverse of the1702hiding order. The stack is reduced in size to stackBottom.17031704Returns OK on success, NOTOK on internal failure.1705********************************************************************/17061707int _RestoreHiddenEdges(graphP theGraph, int stackBottom)1708{1709int e;17101711while (sp_GetCurrentSize(theGraph->theStack) > stackBottom)1712{1713sp_Pop(theGraph->theStack, e);1714if (!gp_IsArc(theGraph, e))1715return NOTOK;1716gp_RestoreEdge(theGraph, e);1717}17181719return OK;1720}17211722/********************************************************************1723gp_HideVertex()17241725Pushes onto the graph's stack and hides all arc nodes of the vertex.1726Additional integers are then pushed so that the result is reversible1727by gp_RestoreVertex(). See that method for details on the expected1728stack segment.17291730Returns OK for success, NOTOK for internal failure.1731********************************************************************/17321733int gp_HideVertex(graphP theGraph, int vertex)1734{1735if (vertex == NIL)1736return NOTOK;17371738return theGraph->functions.fpHideVertex(theGraph, vertex);1739}17401741int _HideVertex(graphP theGraph, int vertex)1742{1743int hiddenEdgeStackBottom = sp_GetCurrentSize(theGraph->theStack);1744int J = gp_GetFirstArc(theGraph, vertex);17451746// Cycle through all the edges, pushing and hiding each1747while (gp_IsArc(theGraph, J))1748{1749sp_Push(theGraph->theStack, J);1750gp_HideEdge(theGraph, J);1751J = gp_GetNextArc(theGraph, J);1752}17531754// Push the additional integers needed by gp_RestoreVertex()1755sp_Push(theGraph->theStack, hiddenEdgeStackBottom);1756sp_Push(theGraph->theStack, NIL);1757sp_Push(theGraph->theStack, NIL);1758sp_Push(theGraph->theStack, NIL);1759sp_Push(theGraph->theStack, NIL);1760sp_Push(theGraph->theStack, NIL);1761sp_Push(theGraph->theStack, vertex);17621763return OK;1764}17651766/********************************************************************1767gp_ContractEdge()17681769Contracts the edge e=(u,v). This hides the edge (both e and its1770twin arc), and it also identifies vertex v with u.1771See gp_IdentifyVertices() for further details.17721773Returns OK for success, NOTOK for internal failure.1774********************************************************************/17751776int gp_ContractEdge(graphP theGraph, int e)1777{1778if (!gp_IsArc(theGraph, e))1779return NOTOK;17801781return theGraph->functions.fpContractEdge(theGraph, e);1782}17831784int _ContractEdge(graphP theGraph, int e)1785{1786int eBefore, u, v;17871788if (!gp_IsArc(theGraph, e))1789return NOTOK;17901791u = theGraph->G[gp_GetTwinArc(theGraph, e)].v;1792v = theGraph->G[e].v;17931794eBefore = gp_GetNextArc(theGraph, e);1795sp_Push(theGraph->theStack, e);1796gp_HideEdge(theGraph, e);17971798return gp_IdentifyVertices(theGraph, u, v, eBefore);1799}18001801/********************************************************************1802gp_IdentifyVertices()18031804Identifies vertex v with vertex u by transferring all adjacencies1805of v to u. Any duplicate edges are removed as described below.1806The non-duplicate edges of v are added to the adjacency list of u1807without disturbing their relative order, and they are added before1808the edge record eBefore in u's list. If eBefore is NIL, then the1809edges are simply appended to u's list.18101811If u and v are adjacent, then gp_HideEdge() is invoked to remove1812the edge e=(u,v). Then, the edges of v that indicate neighbors of1813u are also hidden. This is done by setting the visited flags of1814u's neighbors, then traversing the adjacency list of v. For each1815visited neighbor of v, the edge is hidden because it would duplicate1816an adjacency already expressed in u's list. Finally, the remaining1817edges of v are moved to u's list, and each twin arc is adjusted1818to indicate u as a neighbor rather than v.18191820This routine assumes that the visited flags are clear beforehand,1821and visited flag settings made herein are cleared before returning.18221823The following are pushed, in order, onto the graph's built-in stack:18241) an integer for each hidden edge18252) the stack size before any hidden edges were pushed18263) six integers that indicate u, v and the edges moved from v to u18271828An algorithm that identifies a series of vertices, either through1829directly calling this method or via gp_ContractEdge(), can unwind1830the identifications using gp_RestoreIdentifications(), which1831invokes gp_RestoreVertex() repeatedly.18321833Returns OK on success, NOTOK on internal failure1834********************************************************************/18351836int gp_IdentifyVertices(graphP theGraph, int u, int v, int eBefore)1837{1838return theGraph->functions.fpIdentifyVertices(theGraph, u, v, eBefore);1839}18401841int _IdentifyVertices(graphP theGraph, int u, int v, int eBefore)1842{1843int e = gp_GetNeighborEdgeRecord(theGraph, u, v);1844int hiddenEdgeStackBottom, eBeforePred, J;18451846// If the vertices are adjacent, then the identification is1847// essentially an edge contraction with a bit of fixup.1848if (gp_IsArc(theGraph, e))1849{1850int result = gp_ContractEdge(theGraph, e);18511852// The edge contraction operation pushes one hidden edge then1853// recursively calls this method. This method then pushes K1854// hidden edges then an integer indicating where the top of1855// stack was before the edges were hidden. That integer1856// indicator must be decremented, thereby incrementing the1857// number of hidden edges to K+1.1858// After pushing the K hidden edges and the stackBottom of1859// the hidden edges, the recursive call to this method pushes1860// six more integers to indicate edges that were moved from1861// v to u, so the "hidden edges stackBottom" is in the next1862// position down.1863int hiddenEdgesStackBottomIndex = sp_GetCurrentSize(theGraph->theStack)-7;1864int hiddenEdgesStackBottomValue = sp_Get(theGraph->theStack, hiddenEdgesStackBottomIndex);18651866sp_Set(theGraph->theStack, hiddenEdgesStackBottomIndex, hiddenEdgesStackBottomValue - 1);18671868return result;1869}18701871// Now, u and v are not adjacent. Before we do any edge hiding or1872// moving, we record the current stack size, as this is the1873// stackBottom for the edges that will be hidden next.1874hiddenEdgeStackBottom = sp_GetCurrentSize(theGraph->theStack);18751876// Mark as visited all neighbors of u1877J = gp_GetFirstArc(theGraph, u);1878while (gp_IsArc(theGraph, J))1879{1880if (theGraph->G[theGraph->G[J].v].visited != 0)1881return NOTOK;18821883theGraph->G[theGraph->G[J].v].visited = 1;1884J = gp_GetNextArc(theGraph, J);1885}18861887// For each edge record of v, if the neighbor is visited, then1888// push and hide the edge.1889J = gp_GetFirstArc(theGraph, v);1890while (gp_IsArc(theGraph, J))1891{1892if (theGraph->G[theGraph->G[J].v].visited)1893{1894sp_Push(theGraph->theStack, J);1895gp_HideEdge(theGraph, J);1896}1897J = gp_GetNextArc(theGraph, J);1898}18991900// Mark as unvisited all neighbors of u1901J = gp_GetFirstArc(theGraph, u);1902while (gp_IsArc(theGraph, J))1903{1904theGraph->G[theGraph->G[J].v].visited = 0;1905J = gp_GetNextArc(theGraph, J);1906}19071908// Push the hiddenEdgeStackBottom as a record of how many hidden1909// edges were pushed (also, see above for Contract Edge adjustment)1910sp_Push(theGraph->theStack, hiddenEdgeStackBottom);19111912// Moving v's adjacency list to u is aided by knowing the predecessor1913// of u's eBefore (the edge record in u's list before which the1914// edge records of v will be added).1915eBeforePred = gp_IsArc(theGraph, eBefore)1916? gp_GetPrevArc(theGraph, eBefore)1917: gp_GetLastArc(theGraph, u);19181919// Turns out we only need to record six integers related to the edges1920// being moved in order to easily restore them later.1921sp_Push(theGraph->theStack, eBefore);1922sp_Push(theGraph->theStack, gp_GetLastArc(theGraph, v));1923sp_Push(theGraph->theStack, gp_GetFirstArc(theGraph, v));1924sp_Push(theGraph->theStack, eBeforePred);1925sp_Push(theGraph->theStack, u);1926sp_Push(theGraph->theStack, v);19271928// For the remaining edge records of v, reassign the 'v' member1929// of each twin arc to indicate u rather than v.1930J = gp_GetFirstArc(theGraph, v);1931while (gp_IsArc(theGraph, J))1932{1933theGraph->G[gp_GetTwinArc(theGraph, J)].v = u;1934J = gp_GetNextArc(theGraph, J);1935}19361937// If v has any edges left after hiding edges, indicating common neighbors with u, ...1938if (gp_IsArc(theGraph, gp_GetFirstArc(theGraph, v)))1939{1940// Then perform the list union of v into u between eBeforePred and eBefore1941if (gp_IsArc(theGraph, eBeforePred))1942{1943if (gp_IsArc(theGraph, gp_GetFirstArc(theGraph, v)))1944{1945gp_SetNextArc(theGraph, eBeforePred, gp_GetFirstArc(theGraph, v));1946gp_SetPrevArc(theGraph, gp_GetFirstArc(theGraph, v), eBeforePred);1947}1948}1949else1950{1951gp_SetFirstArc(theGraph, u, gp_GetFirstArc(theGraph, v));1952}19531954if (gp_IsArc(theGraph, eBefore))1955{1956if (gp_IsArc(theGraph, gp_GetLastArc(theGraph, v)))1957{1958gp_SetNextArc(theGraph, gp_GetLastArc(theGraph, v), eBefore);1959gp_SetPrevArc(theGraph, eBefore, gp_GetLastArc(theGraph, v));1960}1961}1962else1963{1964gp_SetLastArc(theGraph, u, gp_GetLastArc(theGraph, v));1965}19661967gp_SetFirstArc(theGraph, v, NIL);1968gp_SetLastArc(theGraph, v, NIL);1969}19701971return OK;1972}19731974/********************************************************************1975gp_RestoreVertex()19761977This method assumes the built-in graph stack contents are the result1978of vertex hide, vertex identify and edge contract operations.1979This content consists of segments of integers, each segment1980corresponding to the removal of a vertex during an edge contraction1981or vertex identification in which a vertex v was merged into a1982vertex u. The segment contains two blocks of integers.1983The first block contains information about u, v, the edge records1984in v's adjacency list that were added to u, and where in u's1985adjacency list they were added. The second block of integers1986contains a list of edges incident to v that were hidden from the1987graph because they were incident to neighbors of v that were also1988neighbors of u (so they would have produced duplicate edges had1989they been left in v's adjacency list when it was merged with u's1990adjacency list).19911992This method pops the first block of the segment off the stack and1993uses the information to help remove v's adjacency list from u and1994restore it into v. Then, the second block is removed from the1995stack, and each indicated edge is restored from the hidden state.19961997It is anticipated that this method will be overloaded by extension1998algorithms to perform some processing as each vertex is restored.1999Before restoration, the topmost segment has the following structure:20002001... FHE ... LHE HESB e_u_succ e_v_last e_v_first e_u_pred u v2002^------------|20032004FHE = First hidden edge2005LHE = Last hidden edge2006HESB = Hidden edge stack bottom2007e_u_succ, e_u_pred = The edges of u between which the edges of v2008were inserted. NIL can appear if the edges of v2009were added to the beginning or end of u's list2010e_v_first, e_v_last = The first and last edges of v's list, once2011the hidden edges were removed20122013Returns OK for success, NOTOK for internal failure.2014********************************************************************/20152016int gp_RestoreVertex(graphP theGraph)2017{2018return theGraph->functions.fpRestoreVertex(theGraph);2019}20202021int _RestoreVertex(graphP theGraph)2022{2023int u, v, e_u_succ, e_u_pred, e_v_first, e_v_last, HESB, J;20242025if (sp_GetCurrentSize(theGraph->theStack) < 7)2026return NOTOK;20272028sp_Pop(theGraph->theStack, v);2029sp_Pop(theGraph->theStack, u);2030sp_Pop(theGraph->theStack, e_u_pred);2031sp_Pop(theGraph->theStack, e_v_first);2032sp_Pop(theGraph->theStack, e_v_last);2033sp_Pop(theGraph->theStack, e_u_succ);20342035// If u is not NIL, then vertex v was identified with u. Otherwise, v was2036// simply hidden, so we skip to restoring the hidden edges.2037if (u != NIL)2038{2039// Remove v's adjacency list from u, including accounting for degree 0 case2040if (gp_IsArc(theGraph, e_u_pred))2041{2042gp_SetNextArc(theGraph, e_u_pred, e_u_succ);2043// If the successor edge exists, link it to the predecessor,2044// otherwise the predecessor is the new last arc2045if (gp_IsArc(theGraph, e_u_succ))2046gp_SetPrevArc(theGraph, e_u_succ, e_u_pred);2047else2048gp_SetLastArc(theGraph, u, e_u_pred);2049}2050else if (gp_IsArc(theGraph, e_u_succ))2051{2052// The successor arc exists, but not the predecessor,2053// so the successor is the new first arc2054gp_SetPrevArc(theGraph, e_u_succ, NIL);2055gp_SetFirstArc(theGraph, u, e_u_succ);2056}2057else2058{2059// Just in case u was degree zero2060gp_SetFirstArc(theGraph, u, NIL);2061gp_SetLastArc(theGraph, u, NIL);2062}20632064// Place v's adjacency list into v, including accounting for degree 0 case2065gp_SetFirstArc(theGraph, v, e_v_first);2066gp_SetLastArc(theGraph, v, e_v_last);2067if (gp_IsArc(theGraph, e_v_first))2068gp_SetPrevArc(theGraph, e_v_first, NIL);2069if (gp_IsArc(theGraph, e_v_last))2070gp_SetPrevArc(theGraph, e_v_last, NIL);20712072// For each edge record restored to v's adjacency list, reassign the 'v' member2073// of each twin arc to indicate v rather than u.2074J = e_v_first;2075while (gp_IsArc(theGraph, J))2076{2077theGraph->G[gp_GetTwinArc(theGraph, J)].v = v;20782079if (J == e_v_last)2080J = NIL;2081else2082J = gp_GetNextArc(theGraph, J);2083}2084}20852086// Restore the hidden edges of v, if any2087sp_Pop(theGraph->theStack, HESB);2088return _RestoreHiddenEdges(theGraph, HESB);2089}20902091/********************************************************************2092gp_RestoreVertices()20932094This method assumes the built-in graph stack has content consistent2095with numerous vertex identification or edge contraction operations.2096This method unwinds the stack, moving edges back to their original2097vertex owners and restoring hidden edges.2098This method is a simple iterator that invokes gp_RestoreVertex()2099until the stack is empty, so extension algorithms are more likely2100to overload gp_RestoreVertex().21012102Returns OK for success, NOTOK for internal failure.2103********************************************************************/21042105int gp_RestoreVertices(graphP theGraph)2106{2107while (sp_NonEmpty(theGraph->theStack))2108{2109if (gp_RestoreVertex(theGraph) != OK)2110return NOTOK;2111}21122113return OK;2114}21152116/****************************************************************************2117_ComputeArcType()2118This is just a little helper function that automates a sequence of decisions2119that has to be made a number of times.2120An edge record is being added to the adjacency list of a; it indicates that2121b is a neighbor. The edgeType can be either 'tree' (EDGE_DFSPARENT or2122EDGE_DFSCHILD) or 'cycle' (EDGE_BACK or EDGE_FORWARD).2123If a or b is a root copy, we translate to the non-virtual counterpart,2124then wedetermine which has the lesser DFI. If a has the lower DFI then the2125edge record is a tree edge to a child (EDGE_DFSCHILD) if edgeType indicates2126a tree edge. If edgeType indicates a cycle edge, then it is a forward cycle2127edge (EDGE_FORWARD) to a descendant.2128Symmetric conditions define the types for a > b.2129****************************************************************************/21302131int _ComputeArcType(graphP theGraph, int a, int b, int edgeType)2132{2133if (a >= theGraph->N)2134a = theGraph->V[a - theGraph->N].DFSParent;2135if (b >= theGraph->N)2136b = theGraph->V[b - theGraph->N].DFSParent;21372138if (a < b)2139return edgeType == EDGE_DFSPARENT || edgeType == EDGE_DFSCHILD ? EDGE_DFSCHILD : EDGE_FORWARD;21402141return edgeType == EDGE_DFSPARENT || edgeType == EDGE_DFSCHILD ? EDGE_DFSPARENT : EDGE_BACK;2142}21432144/****************************************************************************2145_SetEdgeType()2146When we are restoring an edge, we must restore its type (tree edge or cycle edge).2147We can deduce what the type was based on other information in the graph. Each2148arc of the edge gets the appropriate type setting (parent/child or back/forward).2149This method runs in constant time plus the degree of vertex u, or constant2150time if u is known to have a degree bound by a constant.2151****************************************************************************/21522153int _SetEdgeType(graphP theGraph, int u, int v)2154{2155int e, eTwin, u_orig, v_orig, N;21562157// If u or v is a virtual vertex (a root copy), then get the non-virtual counterpart.2158N = theGraph->N;2159u_orig = u < N ? u : (theGraph->V[u - N].DFSParent);2160v_orig = v < N ? v : (theGraph->V[v - N].DFSParent);21612162// Get the edge for which we will set the type21632164e = gp_GetNeighborEdgeRecord(theGraph, u, v);2165eTwin = gp_GetTwinArc(theGraph, e);21662167// If u_orig is the parent of v_orig, or vice versa, then the edge is a tree edge21682169if (theGraph->V[v_orig].DFSParent == u_orig ||2170theGraph->V[u_orig].DFSParent == v_orig)2171{2172if (u_orig > v_orig)2173{2174theGraph->G[e].type = EDGE_DFSPARENT;2175theGraph->G[eTwin].type = EDGE_DFSCHILD;2176}2177else2178{2179theGraph->G[eTwin].type = EDGE_DFSPARENT;2180theGraph->G[e].type = EDGE_DFSCHILD;2181}2182}21832184// Otherwise it is a back edge21852186else2187{2188if (u_orig > v_orig)2189{2190theGraph->G[e].type = EDGE_BACK;2191theGraph->G[eTwin].type = EDGE_FORWARD;2192}2193else2194{2195theGraph->G[eTwin].type = EDGE_BACK;2196theGraph->G[e].type = EDGE_FORWARD;2197}2198}21992200return OK;2201}22022203/********************************************************************2204_DeleteUnmarkedEdgesInBicomp()22052206This function deletes from a given biconnected component all edges2207whose visited member is zero.22082209The stack is used but preserved. In debug mode, NOTOK can result if2210there is a stack overflow. This method pushes at most one integer2211per vertex in the bicomp.22122213Returns OK on success, NOTOK on implementation failure2214********************************************************************/22152216int _DeleteUnmarkedEdgesInBicomp(graphP theGraph, int BicompRoot)2217{2218int V, J;2219int stackBottom = sp_GetCurrentSize(theGraph->theStack);22202221sp_Push(theGraph->theStack, BicompRoot);2222while (sp_GetCurrentSize(theGraph->theStack) > stackBottom)2223{2224sp_Pop(theGraph->theStack, V);22252226J = gp_GetFirstArc(theGraph, V);2227while (gp_IsArc(theGraph, J))2228{2229if (theGraph->G[J].type == EDGE_DFSCHILD)2230sp_Push(theGraph->theStack, theGraph->G[J].v);22312232if (!theGraph->G[J].visited)2233J = gp_DeleteEdge(theGraph, J, 0);2234else J = gp_GetNextArc(theGraph, J);2235}2236}2237return OK;2238}22392240/********************************************************************2241_ClearInvertedFlagsInBicomp()22422243This function clears the inverted flag markers on any edges in a2244given biconnected component.22452246The stack is used but preserved. In debug mode, NOTOK can result if2247there is a stack overflow. This method pushes at most one integer2248per vertex in the bicomp.22492250Returns OK on success, NOTOK on implementation failure2251********************************************************************/22522253int _ClearInvertedFlagsInBicomp(graphP theGraph, int BicompRoot)2254{2255int V, J;2256int stackBottom = sp_GetCurrentSize(theGraph->theStack);22572258sp_Push(theGraph->theStack, BicompRoot);2259while (sp_GetCurrentSize(theGraph->theStack) > stackBottom)2260{2261sp_Pop(theGraph->theStack, V);22622263J = gp_GetFirstArc(theGraph, V);2264while (gp_IsArc(theGraph, J))2265{2266if (theGraph->G[J].type == EDGE_DFSCHILD)2267{2268sp_Push(theGraph->theStack, theGraph->G[J].v);2269CLEAR_EDGEFLAG_INVERTED(theGraph, J);2270}22712272J = gp_GetNextArc(theGraph, J);2273}2274}2275return OK;2276}22772278/********************************************************************2279_GetBicompSize()22802281Determine the number of vertices in the bicomp.22822283The stack is used but preserved. In debug mode, NOTOK can result if2284there is a stack overflow. This method pushes at most one integer2285per vertex in the bicomp.22862287Returns a positive number on success, NOTOK on implementation failure2288********************************************************************/22892290int _GetBicompSize(graphP theGraph, int BicompRoot)2291{2292int V, J;2293int theSize = 0;2294int stackBottom = sp_GetCurrentSize(theGraph->theStack);22952296sp_Push(theGraph->theStack, BicompRoot);2297while (sp_GetCurrentSize(theGraph->theStack) > stackBottom)2298{2299sp_Pop(theGraph->theStack, V);2300theSize++;2301J = gp_GetFirstArc(theGraph, V);2302while (gp_IsArc(theGraph, J))2303{2304if (theGraph->G[J].type == EDGE_DFSCHILD)2305sp_Push(theGraph->theStack, theGraph->G[J].v);23062307J = gp_GetNextArc(theGraph, J);2308}2309}2310return theSize;2311}23122313/********************************************************************2314debugNOTOK()2315This function provides a non-void wrapper for exit().2316This is useful for debugging as it allows compilation of an exit2317command in places where NOTOK is returned.2318In exhaustive testing, we want to bail on the first NOTOK that occurs.2319Comment out the exit() call to get a stack trace.2320********************************************************************/23212322int debugNOTOK()2323{2324//exit(-1);2325return 0; // NOTOK is normally defined to be zero2326}232723282329