Path: blob/master/sage/graphs/planarity/graphIsolator.c
4079 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#define GRAPHISOLATOR_C4546#include "graph.h"4748/* Imported functions */4950extern void _FillVisitedFlags(graphP, int);5152extern int _GetNextVertexOnExternalFace(graphP theGraph, int curVertex, int *pPrevLink);53extern int _JoinBicomps(graphP theGraph);5455extern int _ChooseTypeOfNonplanarityMinor(graphP theGraph, int I, int R);5657/* Private function declarations (exported within system) */5859int _IsolateKuratowskiSubgraph(graphP theGraph, int I, int R);6061int _FindUnembeddedEdgeToAncestor(graphP theGraph, int cutVertex,62int *pAncestor, int *pDescendant);63int _FindUnembeddedEdgeToCurVertex(graphP theGraph, int cutVertex,64int *pDescendant);65int _FindUnembeddedEdgeToSubtree(graphP theGraph, int ancestor,66int SubtreeRoot, int *pDescendant);6768int _MarkPathAlongBicompExtFace(graphP theGraph, int startVert, int endVert);6970int _AddAndMarkEdge(graphP theGraph, int ancestor, int descendant);71void _AddBackEdge(graphP theGraph, int ancestor, int descendant);72int _DeleteUnmarkedVerticesAndEdges(graphP theGraph);7374int _InitializeIsolatorContext(graphP theGraph);7576int _IsolateMinorA(graphP theGraph);77int _IsolateMinorB(graphP theGraph);78int _IsolateMinorC(graphP theGraph);79int _IsolateMinorD(graphP theGraph);80int _IsolateMinorE(graphP theGraph);8182int _IsolateMinorE1(graphP theGraph);83int _IsolateMinorE2(graphP theGraph);84int _IsolateMinorE3(graphP theGraph);85int _IsolateMinorE4(graphP theGraph);8687int _GetLeastAncestorConnection(graphP theGraph, int cutVertex);88int _MarkDFSPathsToDescendants(graphP theGraph);89int _AddAndMarkUnembeddedEdges(graphP theGraph);9091/****************************************************************************92gp_IsolateKuratowskiSubgraph()93****************************************************************************/9495int _IsolateKuratowskiSubgraph(graphP theGraph, int I, int R)96{97int RetVal;9899/* A subgraph homeomorphic to K_{3,3} or K_5 will be isolated by using the visited100flags, 1=keep edge/vertex and 0=omit. Here we initialize to omit all, then we101subsequently set visited to 1 on all edges and vertices in the homeomorph. */102103_FillVisitedFlags(theGraph, 0);104105/* Next, we determine which of the non-planarity Minors was encountered106and the principal bicomp on which the isolator will focus attention. */107108if (_ChooseTypeOfNonplanarityMinor(theGraph, I, R) != OK)109return NOTOK;110111if (_InitializeIsolatorContext(theGraph) != OK)112return NOTOK;113114/* Call the appropriate isolator */115116if (theGraph->IC.minorType & MINORTYPE_A)117RetVal = _IsolateMinorA(theGraph);118else if (theGraph->IC.minorType & MINORTYPE_B)119RetVal = _IsolateMinorB(theGraph);120else if (theGraph->IC.minorType & MINORTYPE_C)121RetVal = _IsolateMinorC(theGraph);122else if (theGraph->IC.minorType & MINORTYPE_D)123RetVal = _IsolateMinorD(theGraph);124else if (theGraph->IC.minorType & MINORTYPE_E)125RetVal = _IsolateMinorE(theGraph);126else127RetVal = NOTOK;128129/* Delete the unmarked edges and vertices, and return */130131if (RetVal == OK)132RetVal = _DeleteUnmarkedVerticesAndEdges(theGraph);133134return RetVal;135}136137/****************************************************************************138_InitializeIsolatorContext()139****************************************************************************/140141int _InitializeIsolatorContext(graphP theGraph)142{143isolatorContextP IC = &theGraph->IC;144145/* Obtains the edges connecting X and Y to ancestors of the current vertex */146147if (_FindUnembeddedEdgeToAncestor(theGraph, IC->x, &IC->ux, &IC->dx) != TRUE ||148_FindUnembeddedEdgeToAncestor(theGraph, IC->y, &IC->uy, &IC->dy) != TRUE)149return NOTOK;150151/* For Minor B, we seek the last pertinent child biconnected component, which152is externally active, and obtain the DFS child in its root edge.153This child is the subtree root containing vertices with connections to154both the current vertex and an ancestor of the current vertex. */155156if (theGraph->IC.minorType & MINORTYPE_B)157{158int SubtreeRoot = LCGetPrev(theGraph->BicompLists,159theGraph->V[IC->w].pertinentBicompList, NIL);160161IC->uz = theGraph->V[SubtreeRoot].Lowpoint;162163if (_FindUnembeddedEdgeToSubtree(theGraph, IC->v, SubtreeRoot, &IC->dw) != TRUE ||164_FindUnembeddedEdgeToSubtree(theGraph, IC->uz, SubtreeRoot, &IC->dz) != TRUE)165return NOTOK;166}167168/* For all other minors, we obtain */169170else171{172if (_FindUnembeddedEdgeToCurVertex(theGraph, IC->w, &IC->dw) != TRUE)173return NOTOK;174175if (theGraph->IC.minorType & MINORTYPE_E)176if (_FindUnembeddedEdgeToAncestor(theGraph, IC->z, &IC->uz, &IC->dz) != TRUE)177return NOTOK;178}179180return OK;181}182183/****************************************************************************184_IsolateMinorA(): Isolate a K3,3 homeomorph185****************************************************************************/186187int _IsolateMinorA(graphP theGraph)188{189isolatorContextP IC = &theGraph->IC;190191if (_MarkPathAlongBicompExtFace(theGraph, IC->r, IC->r) != OK ||192theGraph->functions.fpMarkDFSPath(theGraph, MIN(IC->ux, IC->uy), IC->r) != OK ||193_MarkDFSPathsToDescendants(theGraph) != OK ||194_JoinBicomps(theGraph) != OK ||195_AddAndMarkUnembeddedEdges(theGraph) != OK)196return NOTOK;197198return OK;199}200201/****************************************************************************202_IsolateMinorB(): Isolate a K3,3 homeomorph203****************************************************************************/204205int _IsolateMinorB(graphP theGraph)206{207isolatorContextP IC = &theGraph->IC;208209if (_MarkPathAlongBicompExtFace(theGraph, IC->r, IC->r) != OK ||210theGraph->functions.fpMarkDFSPath(theGraph, MIN3(IC->ux,IC->uy,IC->uz),211MAX3(IC->ux,IC->uy,IC->uz)) != OK ||212_MarkDFSPathsToDescendants(theGraph) != OK ||213_JoinBicomps(theGraph) != OK ||214_AddAndMarkUnembeddedEdges(theGraph) != OK)215return NOTOK;216217return OK;218}219220/****************************************************************************221_IsolateMinorC(): Isolate a K3,3 homeomorph222****************************************************************************/223224int _IsolateMinorC(graphP theGraph)225{226isolatorContextP IC = &theGraph->IC;227228if (theGraph->G[IC->px].type == VERTEX_HIGH_RXW)229{230int highY = theGraph->G[IC->py].type == VERTEX_HIGH_RYW231? IC->py : IC->y;232if (_MarkPathAlongBicompExtFace(theGraph, IC->r, highY) != OK)233return NOTOK;234}235else236{237if (_MarkPathAlongBicompExtFace(theGraph, IC->x, IC->r) != OK)238return NOTOK;239}240241if (_MarkDFSPathsToDescendants(theGraph) != OK ||242theGraph->functions.fpMarkDFSPath(theGraph, MIN(IC->ux, IC->uy), IC->r) != OK ||243_JoinBicomps(theGraph) != OK ||244_AddAndMarkUnembeddedEdges(theGraph) != OK)245return NOTOK;246247return OK;248}249250/****************************************************************************251_IsolateMinorD(): Isolate a K3,3 homeomorph252****************************************************************************/253254int _IsolateMinorD(graphP theGraph)255{256isolatorContextP IC = &theGraph->IC;257258if (_MarkPathAlongBicompExtFace(theGraph, IC->x, IC->y) != OK ||259theGraph->functions.fpMarkDFSPath(theGraph, MIN(IC->ux, IC->uy), IC->r) != OK ||260_MarkDFSPathsToDescendants(theGraph) != OK ||261_JoinBicomps(theGraph) != OK ||262_AddAndMarkUnembeddedEdges(theGraph) != OK)263return NOTOK;264265return OK;266}267268/****************************************************************************269_IsolateMinorE()270****************************************************************************/271272int _IsolateMinorE(graphP theGraph)273{274isolatorContextP IC = &theGraph->IC;275276/* Minor E1: Isolate a K3,3 homeomorph */277278if (IC->z != IC->w)279return _IsolateMinorE1(theGraph);280281/* Minor E2: Isolate a K3,3 homeomorph */282283if (IC->uz > MAX(IC->ux, IC->uy))284return _IsolateMinorE2(theGraph);285286/* Minor E3: Isolate a K3,3 homeomorph */287288if (IC->uz < MAX(IC->ux, IC->uy) && IC->ux != IC->uy)289return _IsolateMinorE3(theGraph);290291/* Minor E4: Isolate a K3,3 homeomorph */292293else if (IC->x != IC->px || IC->y != IC->py)294return _IsolateMinorE4(theGraph);295296/* Minor E: Isolate a K5 homeomorph */297298if (_MarkPathAlongBicompExtFace(theGraph, IC->r, IC->r) != OK ||299theGraph->functions.fpMarkDFSPath(theGraph, MIN3(IC->ux, IC->uy, IC->uz), IC->r) != OK ||300_MarkDFSPathsToDescendants(theGraph) != OK ||301_JoinBicomps(theGraph) != OK ||302_AddAndMarkUnembeddedEdges(theGraph) != OK)303return NOTOK;304305return OK;306}307308/****************************************************************************309_IsolateMinorE1()310311Reduce to Minor C if the vertex Z responsible for external activity312below the X-Y path does not equal the pertinent vertex W.313****************************************************************************/314315int _IsolateMinorE1(graphP theGraph)316{317isolatorContextP IC = &theGraph->IC;318319if (theGraph->G[IC->z].type == VERTEX_LOW_RXW)320{321theGraph->G[IC->px].type = VERTEX_HIGH_RXW;322IC->x=IC->z; IC->ux=IC->uz; IC->dx=IC->dz;323}324else if (theGraph->G[IC->z].type == VERTEX_LOW_RYW)325{326theGraph->G[IC->py].type = VERTEX_HIGH_RYW;327IC->y=IC->z; IC->uy=IC->uz; IC->dy=IC->dz;328}329else return NOTOK;330331IC->z = IC->uz = IC->dz = NIL;332theGraph->IC.minorType ^= MINORTYPE_E;333theGraph->IC.minorType |= (MINORTYPE_C|MINORTYPE_E1);334return _IsolateMinorC(theGraph);335}336337/****************************************************************************338_IsolateMinorE2()339340If uZ (which is the ancestor of I that is adjacent to Z) is a341descendant of both uY and uX, then we reduce to Minor A342****************************************************************************/343344int _IsolateMinorE2(graphP theGraph)345{346isolatorContextP IC = &theGraph->IC;347348_FillVisitedFlags(theGraph, 0);349350IC->v = IC->uz;351IC->dw = IC->dz;352IC->z = IC->uz = IC->dz = NIL;353354theGraph->IC.minorType ^= MINORTYPE_E;355theGraph->IC.minorType |= (MINORTYPE_A|MINORTYPE_E2);356return _IsolateMinorA(theGraph);357}358359/****************************************************************************360_IsolateMinorE3()361****************************************************************************/362363int _IsolateMinorE3(graphP theGraph)364{365isolatorContextP IC = &theGraph->IC;366367if (IC->ux < IC->uy)368{369if (_MarkPathAlongBicompExtFace(theGraph, IC->r, IC->px) != OK ||370_MarkPathAlongBicompExtFace(theGraph, IC->w, IC->y) != OK)371return NOTOK;372}373else374{375if (_MarkPathAlongBicompExtFace(theGraph, IC->x, IC->w) != OK ||376_MarkPathAlongBicompExtFace(theGraph, IC->py, IC->r) != OK)377return NOTOK;378}379380if (theGraph->functions.fpMarkDFSPath(theGraph, MIN3(IC->ux, IC->uy, IC->uz), IC->r) != OK ||381_MarkDFSPathsToDescendants(theGraph) != OK ||382_JoinBicomps(theGraph) != OK ||383_AddAndMarkUnembeddedEdges(theGraph) != OK)384return NOTOK;385386theGraph->IC.minorType |= MINORTYPE_E3;387return OK;388}389390/****************************************************************************391_IsolateMinorE4()392****************************************************************************/393394int _IsolateMinorE4(graphP theGraph)395{396isolatorContextP IC = &theGraph->IC;397398if (IC->px != IC->x)399{400if (_MarkPathAlongBicompExtFace(theGraph, IC->r, IC->w) != OK ||401_MarkPathAlongBicompExtFace(theGraph, IC->py, IC->r) != OK)402return NOTOK;403}404else405{406if (_MarkPathAlongBicompExtFace(theGraph, IC->r, IC->px) != OK ||407_MarkPathAlongBicompExtFace(theGraph, IC->w, IC->r) != OK)408return NOTOK;409}410411if (theGraph->functions.fpMarkDFSPath(theGraph, MIN3(IC->ux, IC->uy, IC->uz),412MAX3(IC->ux, IC->uy, IC->uz)) != OK ||413_MarkDFSPathsToDescendants(theGraph) != OK ||414_JoinBicomps(theGraph) != OK ||415_AddAndMarkUnembeddedEdges(theGraph) != OK)416return NOTOK;417418theGraph->IC.minorType |= MINORTYPE_E4;419return OK;420}421422/****************************************************************************423_GetLeastAncestorConnection()424425This function searches for an ancestor of the current vertex I adjacent by a426cycle edge to the given cutVertex or one of its DFS descendants appearing in427a separated bicomp. The given cutVertex is assumed to be externally active428such that either the leastAncestor or the lowpoint of a separated DFS child429is less than I. We obtain the minimum possible connection from the cutVertex430to an ancestor of I.431NOTE: the separatedDFSChildList is sorted by lowpoint, so the first entry432has the lowest lowpoint, i.e. is the "most" externally active.433This is why we only need to look at the first entry.434****************************************************************************/435436int _GetLeastAncestorConnection(graphP theGraph, int cutVertex)437{438int subtreeRoot = theGraph->V[cutVertex].separatedDFSChildList;439int ancestor = theGraph->V[cutVertex].leastAncestor;440441if (subtreeRoot != NIL &&442ancestor > theGraph->V[subtreeRoot].Lowpoint)443ancestor = theGraph->V[subtreeRoot].Lowpoint;444445return ancestor;446}447448/****************************************************************************449_FindUnembeddedEdgeToAncestor()450451This function searches for an ancestor of the current vertex I adjacent by a452cycle edge to the given cutVertex or one of its DFS descendants appearing in453a separated bicomp.454455The given cutVertex is assumed to be externally active such that either the456leastAncestor or the lowpoint of a separated DFS child is less than I.457We obtain the minimum possible connection from the cutVertex to an ancestor458of I, then compute the descendant accordingly.459460NOTE: the separatedDFSChildList is sorted by lowpoint, so the first entry461has the lowest lowpoint, i.e. is the "most" externally active.462This is why we only need to look at the first entry. Even if the463cutVertex is externally active but pertinent, any internally active464pertinent child bicomps would be later in the separatedDFSChildList465because their internal activity suggests a higher lowpoint value.466467Returns TRUE if found, FALSE otherwise.468****************************************************************************/469470int _FindUnembeddedEdgeToAncestor(graphP theGraph, int cutVertex,471int *pAncestor, int *pDescendant)472{473*pAncestor = _GetLeastAncestorConnection(theGraph, cutVertex);474475if (*pAncestor == theGraph->V[cutVertex].leastAncestor)476{477*pDescendant = cutVertex;478return TRUE;479}480else481{482int subtreeRoot = theGraph->V[cutVertex].separatedDFSChildList;483484return _FindUnembeddedEdgeToSubtree(theGraph, *pAncestor,485subtreeRoot, pDescendant);486}487}488489/****************************************************************************490_FindUnembeddedEdgeToCurVertex()491492Given the current vertex I, we search for an edge connecting I to either493a given pertinent vertex W or one of its DFS descendants in the subtree494indicated by the the last pertinent child biconnected component.495Returns TRUE if founds, FALSE otherwise.496****************************************************************************/497498int _FindUnembeddedEdgeToCurVertex(graphP theGraph, int cutVertex, int *pDescendant)499{500int RetVal = TRUE, I = theGraph->IC.v;501502if (theGraph->V[cutVertex].adjacentTo != NIL)503*pDescendant = cutVertex;504else505{506int subtreeRoot = theGraph->V[cutVertex].pertinentBicompList;507508RetVal = _FindUnembeddedEdgeToSubtree(theGraph, I,509subtreeRoot, pDescendant);510}511512return RetVal;513}514515/****************************************************************************516_FindUnembeddedEdgeToSubtree()517518Given the root vertex of a DFS subtree and an ancestor of that subtree,519find a vertex in the subtree that is adjacent to the ancestor by a520cycle edge.521Returns TRUE if found, FALSE if not found.522****************************************************************************/523524int _FindUnembeddedEdgeToSubtree(graphP theGraph, int ancestor,525int SubtreeRoot, int *pDescendant)526{527int J, Z, ZNew;528529*pDescendant = NIL;530531/* If SubtreeRoot is a root copy, then we change to the DFS child in the532DFS tree root edge of the bicomp rooted by SubtreeRoot. */533534if (SubtreeRoot >= theGraph->N)535SubtreeRoot -= theGraph->N;536537/* Find the least descendant of the cut vertex incident to the ancestor. */538539J = theGraph->V[ancestor].fwdArcList;540while (gp_IsArc(theGraph, J))541{542if (theGraph->G[J].v >= SubtreeRoot)543{544if (*pDescendant == NIL || *pDescendant > theGraph->G[J].v)545*pDescendant = theGraph->G[J].v;546}547548J = gp_GetNextArc(theGraph, J);549if (J == theGraph->V[ancestor].fwdArcList)550J = NIL;551}552553if (*pDescendant == NIL)554return FALSE;555556/* Make sure the identified descendant actually descends from the cut vertex */557558Z = *pDescendant;559while (Z != SubtreeRoot)560{561ZNew = theGraph->V[Z].DFSParent;562if (ZNew == NIL || ZNew == Z)563return FALSE;564Z = ZNew;565}566567/* Return successfully */568569return TRUE;570}571572573/****************************************************************************574_MarkPathAlongBicompExtFace()575576Sets the visited flags of vertices and edges on the external face of a577bicomp from startVert to endVert, inclusive, by following the 'first' arc578link out of each visited vertex.579****************************************************************************/580581int _MarkPathAlongBicompExtFace(graphP theGraph, int startVert, int endVert)582{583int Z, ZPrevLink, ZPrevArc;584585/* Mark the start vertex (and if it is a root copy, mark the parent copy too. */586587theGraph->G[startVert].visited = 1;588589/* For each vertex visited after the start vertex, mark the vertex and the590edge used to get there. Stop after marking the ending vertex. */591592Z = startVert;593ZPrevLink = 1;594do {595Z = _GetNextVertexOnExternalFace(theGraph, Z, &ZPrevLink);596597ZPrevArc = gp_GetArc(theGraph, Z, ZPrevLink);598599theGraph->G[ZPrevArc].visited = 1;600theGraph->G[gp_GetTwinArc(theGraph, ZPrevArc)].visited = 1;601theGraph->G[Z].visited = 1;602603} while (Z != endVert);604605return OK;606}607608/****************************************************************************609_MarkDFSPath()610611Sets visited flags of vertices and edges from descendant to ancestor,612including root copy vertices, and including the step of hopping from613a root copy to its parent copy.614615The DFSParent of a vertex indicates the next vertex to visit, so we616search the adjacency list looking for the edge leading either to the617DFSParent or to a root copy of the DFSParent. We start by marking the618descendant, then traverse up the DFS tree, stopping after we mark619the ancestor.620****************************************************************************/621622int _MarkDFSPath(graphP theGraph, int ancestor, int descendant)623{624int J, parent, Z, N;625626N = theGraph->N;627628/* If we are marking from a root vertex upward, then go up to the parent629copy before starting the loop */630631if (descendant >= N)632descendant = theGraph->V[descendant-N].DFSParent;633634/* Mark the lowest vertex (i.e. the descendant with the highest number) */635theGraph->G[descendant].visited = 1;636637/* Mark all ancestors of the lowest vertex, and the edges used to reach638them, up to the given ancestor vertex. */639640while (descendant != ancestor)641{642/* Get the parent vertex */643644parent = theGraph->V[descendant].DFSParent;645646/* If the descendant was a DFS tree root, then obviously647we aren't going to find the ancestor, so something is wrong.*/648649if (parent == NIL || parent == descendant)650return NOTOK;651652/* Find the edge from descendant that leads either to653parent or to a root copy of the parent.654When the edge is found, mark it and break the loop */655656J = gp_GetFirstArc(theGraph, descendant);657while (gp_IsArc(theGraph, J))658{659Z = theGraph->G[J].v;660if ((Z < N && Z == parent) ||661(Z >= N && theGraph->V[Z-N].DFSParent == parent))662{663theGraph->G[J].visited = 1;664theGraph->G[gp_GetTwinArc(theGraph, J)].visited = 1;665break;666}667J = gp_GetNextArc(theGraph, J);668}669670/* Mark the parent copy of the DFS parent */671theGraph->G[parent].visited = 1;672673/* Hop to the parent */674descendant = parent;675}676677return OK;678}679680/****************************************************************************681_MarkDFSPathsToDescendants()682****************************************************************************/683684int _MarkDFSPathsToDescendants(graphP theGraph)685{686isolatorContextP IC = &theGraph->IC;687688if (theGraph->functions.fpMarkDFSPath(theGraph, IC->x, IC->dx) != OK ||689theGraph->functions.fpMarkDFSPath(theGraph, IC->y, IC->dy) != OK)690return NOTOK;691692if (IC->dw != NIL)693if (theGraph->functions.fpMarkDFSPath(theGraph, IC->w, IC->dw) != OK)694return NOTOK;695696if (IC->dz != NIL)697if (theGraph->functions.fpMarkDFSPath(theGraph, IC->w, IC->dz) != OK)698return NOTOK;699700return OK;701}702703/****************************************************************************704_AddAndMarkUnembeddedEdges()705****************************************************************************/706707int _AddAndMarkUnembeddedEdges(graphP theGraph)708{709isolatorContextP IC = &theGraph->IC;710711if (_AddAndMarkEdge(theGraph, IC->ux, IC->dx) != OK ||712_AddAndMarkEdge(theGraph, IC->uy, IC->dy) != OK)713return NOTOK;714715if (IC->dw != NIL)716if (_AddAndMarkEdge(theGraph, IC->v, IC->dw) != OK)717return NOTOK;718719if (IC->dz != NIL)720if (_AddAndMarkEdge(theGraph, IC->uz, IC->dz) != OK)721return NOTOK;722723return OK;724}725726/****************************************************************************727_AddAndMarkEdge()728729Adds edge records for the edge (ancestor, descendant) and marks the edge730records and vertex structures that represent the edge.731****************************************************************************/732733int _AddAndMarkEdge(graphP theGraph, int ancestor, int descendant)734{735_AddBackEdge(theGraph, ancestor, descendant);736737/* Mark the edge so it is not deleted */738739theGraph->G[ancestor].visited = 1;740theGraph->G[gp_GetFirstArc(theGraph, ancestor)].visited = 1;741theGraph->G[gp_GetFirstArc(theGraph, descendant)].visited = 1;742theGraph->G[descendant].visited = 1;743744return OK;745}746747/****************************************************************************748_AddBackEdge()749750This function transfers the edge records for the edge between the ancestor751and descendant from the forward edge list of the ancestor to the adjacency752lists of the ancestor and descendant.753****************************************************************************/754755void _AddBackEdge(graphP theGraph, int ancestor, int descendant)756{757int fwdArc, backArc;758759/* We get the two edge records of the back edge to embed. */760761fwdArc = theGraph->V[ancestor].fwdArcList;762while (gp_IsArc(theGraph, fwdArc))763{764if (theGraph->G[fwdArc].v == descendant)765break;766767fwdArc = gp_GetNextArc(theGraph, fwdArc);768if (fwdArc == theGraph->V[ancestor].fwdArcList)769fwdArc = NIL;770}771772if (fwdArc == NIL)773return;774775backArc = gp_GetTwinArc(theGraph, fwdArc);776777/* The forward arc is removed from the fwdArcList of the ancestor. */778if (theGraph->V[ancestor].fwdArcList == fwdArc)779{780if (gp_GetNextArc(theGraph, fwdArc) == fwdArc)781theGraph->V[ancestor].fwdArcList = NIL;782else theGraph->V[ancestor].fwdArcList = gp_GetNextArc(theGraph, fwdArc);783}784785gp_SetNextArc(theGraph, gp_GetPrevArc(theGraph, fwdArc), gp_GetNextArc(theGraph, fwdArc));786gp_SetPrevArc(theGraph, gp_GetNextArc(theGraph, fwdArc), gp_GetPrevArc(theGraph, fwdArc));787788/* The forward arc is added to the adjacency list of the ancestor. */789gp_SetPrevArc(theGraph, fwdArc, gp_AdjacencyListEndMark(ancestor));790gp_SetNextArc(theGraph, fwdArc, gp_GetFirstArc(theGraph, ancestor));791gp_SetPrevArc(theGraph, gp_GetFirstArc(theGraph, ancestor), fwdArc);792gp_SetFirstArc(theGraph, ancestor, fwdArc);793794/* The back arc is added to the adjacency list of the descendant. */795gp_SetPrevArc(theGraph, backArc, gp_AdjacencyListEndMark(descendant));796gp_SetNextArc(theGraph, backArc, gp_GetFirstArc(theGraph, descendant));797gp_SetPrevArc(theGraph, gp_GetFirstArc(theGraph, descendant), backArc);798gp_SetFirstArc(theGraph, descendant, backArc);799800theGraph->G[backArc].v = ancestor;801}802803/****************************************************************************804_DeleteUnmarkedVerticesAndEdges()805806For each vertex, traverse its adjacency list and delete all unvisited edges.807****************************************************************************/808809int _DeleteUnmarkedVerticesAndEdges(graphP theGraph)810{811int I, J, fwdArc, descendant;812813/* All of the forward and back arcs of all of the edge records814were removed from the adjacency lists in the planarity algorithm815preprocessing. We now put them back into the adjacency lists816(and we do not mark them), so they can be properly deleted below. */817818for (I = 0; I < theGraph->N; I++)819{820while (theGraph->V[I].fwdArcList != NIL)821{822fwdArc = theGraph->V[I].fwdArcList;823descendant = theGraph->G[fwdArc].v;824_AddBackEdge(theGraph, I, descendant);825}826}827828/* Now we delete all unmarked edges. We don't delete vertices829from the embedding, but the ones we should delete will become830degree zero. */831832for (I = 0; I < theGraph->N; I++)833{834J = gp_GetFirstArc(theGraph, I);835while (gp_IsArc(theGraph, J))836{837if (theGraph->G[J].visited)838J = gp_GetNextArc(theGraph, J);839else J = gp_DeleteEdge(theGraph, J, 0);840}841}842843return OK;844}845846847