Path: blob/master/sage/graphs/planarity/graphK33Search.c
4084 views
/*1Planarity-Related Graph Algorithms Project2Copyright (c) 1997-2010, John M. Boyer3All rights reserved. Includes a reference implementation of the following:45* John M. Boyer. "Simplified O(n) Algorithms for Planar Graph Embedding,6Kuratowski Subgraph Isolation, and Related Problems". Ph.D. Dissertation,7University of Victoria, 2001.89* John M. Boyer and Wendy J. Myrvold. "On the Cutting Edge: Simplified O(n)10Planarity by Edge Addition". Journal of Graph Algorithms and Applications,11Vol. 8, No. 3, pp. 241-273, 2004.1213* John M. Boyer. "A New Method for Efficiently Generating Planar Graph14Visibility Representations". In P. Eades and P. Healy, editors,15Proceedings of the 13th International Conference on Graph Drawing 2005,16Lecture Notes Comput. Sci., Volume 3843, pp. 508-511, Springer-Verlag, 2006.1718Redistribution and use in source and binary forms, with or without modification,19are permitted provided that the following conditions are met:2021* Redistributions of source code must retain the above copyright notice, this22list of conditions and the following disclaimer.2324* Redistributions in binary form must reproduce the above copyright notice, this25list of conditions and the following disclaimer in the documentation and/or26other materials provided with the distribution.2728* Neither the name of the Planarity-Related Graph Algorithms Project nor the names29of its contributors may be used to endorse or promote products derived from this30software without specific prior written permission.3132THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"33AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE34IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE35DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR36ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES37(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;38LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON39ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT40(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS41SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.42*/4344#include "graphK33Search.h"45#include "graphK33Search.private.h"4647extern int K33SEARCH_ID;4849#include "graph.h"5051/* Imported functions */5253extern void _FillVisitedFlags(graphP, int);54extern int _FillVisitedFlagsInBicomp(graphP theGraph, int BicompRoot, int FillValue);55extern int _FillVisitedFlagsInOtherBicomps(graphP theGraph, int BicompRoot, int FillValue);56extern void _FillVisitedFlagsInUnembeddedEdges(graphP theGraph, int FillValue);57extern int _GetBicompSize(graphP theGraph, int BicompRoot);58extern int _HideInternalEdges(graphP theGraph, int vertex);59extern int _RestoreInternalEdges(graphP theGraph, int stackBottom);60extern int _DeleteUnmarkedEdgesInBicomp(graphP theGraph, int BicompRoot);61extern int _ClearInvertedFlagsInBicomp(graphP theGraph, int BicompRoot);62extern int _ComputeArcType(graphP theGraph, int a, int b, int edgeType);63extern int _SetEdgeType(graphP theGraph, int u, int v);6465extern int _GetNextVertexOnExternalFace(graphP theGraph, int curVertex, int *pPrevLink);66extern int _JoinBicomps(graphP theGraph);67extern int _OrientVerticesInBicomp(graphP theGraph, int BicompRoot, int PreserveSigns);68extern int _OrientVerticesInEmbedding(graphP theGraph);69extern void _InvertVertex(graphP theGraph, int V);70extern int _SetVisitedOnPath(graphP theGraph, int u, int v, int w, int x, int visited);71extern int _OrientExternalFacePath(graphP theGraph, int u, int v, int w, int x);7273extern int _ChooseTypeOfNonplanarityMinor(graphP theGraph, int I, int R);74extern int _MarkHighestXYPath(graphP theGraph);7576extern int _IsolateKuratowskiSubgraph(graphP theGraph, int I, int R);7778extern int _FindUnembeddedEdgeToCurVertex(graphP theGraph, int cutVertex, int *pDescendant);79extern int _FindUnembeddedEdgeToSubtree(graphP theGraph, int ancestor, int SubtreeRoot, int *pDescendant);8081extern int _MarkPathAlongBicompExtFace(graphP theGraph, int startVert, int endVert);8283extern int _AddAndMarkEdge(graphP theGraph, int ancestor, int descendant);8485extern int _DeleteUnmarkedVerticesAndEdges(graphP theGraph);8687extern int _IsolateMinorE1(graphP theGraph);88extern int _IsolateMinorE2(graphP theGraph);89extern int _IsolateMinorE3(graphP theGraph);90extern int _IsolateMinorE4(graphP theGraph);9192extern int _GetLeastAncestorConnection(graphP theGraph, int cutVertex);93extern int _MarkDFSPathsToDescendants(graphP theGraph);94extern int _AddAndMarkUnembeddedEdges(graphP theGraph);9596/* Private functions for K_{3,3} searching. */9798int _SearchForK33(graphP theGraph, int I);99100int _SearchForK33InBicomp(graphP theGraph, K33SearchContext *context, int I, int R);101102int _RunExtraK33Tests(graphP theGraph, K33SearchContext *context);103int _SearchForMinorE1(graphP theGraph);104int _FinishIsolatorContextInitialization(graphP theGraph, K33SearchContext *context);105int _SearchForDescendantExternalConnection(graphP theGraph, K33SearchContext *context, int cutVertex, int u_max);106int _GetAdjacentAncestorInRange(graphP theGraph, K33SearchContext *context, int vertex,107int closerAncestor, int fartherAncestor);108int _FindExternalConnectionDescendantEndpoint(graphP theGraph, int ancestor,109int cutVertex, int *pDescendant);110int _SearchForMergeBlocker(graphP theGraph, K33SearchContext *context, int I, int *pMergeBlocker);111int _FindK33WithMergeBlocker(graphP theGraph, K33SearchContext *context, int I, int mergeBlocker);112113int _TestForLowXYPath(graphP theGraph);114int _TestForZtoWPath(graphP theGraph);115int _TestForStraddlingBridge(graphP theGraph, K33SearchContext *context, int u_max);116int _ReduceBicomp(graphP theGraph, K33SearchContext *context, int R);117int _ReduceExternalFacePathToEdge(graphP theGraph, K33SearchContext *context, int u, int x, int edgeType);118int _ReduceXYPathToEdge(graphP theGraph, K33SearchContext *context, int u, int x, int edgeType);119int _RestoreReducedPath(graphP theGraph, K33SearchContext *context, int J);120int _RestoreAndOrientReducedPaths(graphP theGraph, K33SearchContext *context);121122int _IsolateMinorE5(graphP theGraph);123int _IsolateMinorE6(graphP theGraph, K33SearchContext *context);124int _IsolateMinorE7(graphP theGraph, K33SearchContext *context);125126/****************************************************************************127_SearchForK33()128129The strategy involves one special case in which, to achieve a linear time130bound, we must delay the discovery of a K_{3,3} that caused a Walkdown131failure prior to step I. In such cases, vertex I was an ancestor with132a connection to the bicomp on which the Walkdown failed, but it would133have been too costly to find I at the time. So, the bicomp was marked134as non-mergeable prior to some ancestor of I. If this function is135invoked for step I, then we have found the connection from that bicomp136prior to reaching the limiting ancestor of I. The bicomp and I are137therefore part of a K_{3,3} that can now be isolated.138139Otherwise, a Walkdown failure in step I with a non-empty merge stack140would have already resulted in an identified K_{3,3} by minor A, so141we must have an empty merge stack now.142143We must first find all bicomp roots on which the Walkdown has failed144in step I. The fwdArcList of I contains the forward arcs of the145back edges for I that we failed to embed. Each forward arc leads to146a descendant of I that is in a DFS subtree rooted by a child of I,147where the child of I has the greatest DFI that is less than the DFI148of the descendant indicated by the forward arc. Each bicomp root149that represents a vertex is uniquely associated with a DFS child150of the vertex, so once we know the child of I whose subtree contains151a descendant of I that the Walkdown couldn't reach, we can immediately152deduce the root copy of I on which the Walkdown failed.153154For each such root copy of I, we test whether a K_{3,3} homemorph155can be isolated based on that bicomp. If so, then we return it.156Otherwise, each bicomp can be reduced to a 4-cycle and the edges157that the Walkdown failed to embed can be discarded.158****************************************************************************/159160int _SearchForK33(graphP theGraph, int I)161{162int C1, C2, D, e, RetVal=OK, FoundOne;163K33SearchContext *context = NULL;164165gp_FindExtension(theGraph, K33SEARCH_ID, (void *)&context);166if (context == NULL)167return NOTOK;168169/* Before we begin with the standard array of K_{3,3} tests, we handle170one optimization case that may be left over from a prior step171of the embedding algorithm. If the embedding stack is non-empty,172then the Walkdown either halted due to non-planarity minor A or173because of the merge blocking optimization (see CASE 3 in the174function RunExtraK33Tests()). We test for the latter condition,175and if it is found, then we isolate a K_{3,3} and return. */176177if (!sp_IsEmpty(theGraph->theStack))178{179int mergeBlocker;180181if (_SearchForMergeBlocker(theGraph, context, I, &mergeBlocker) != OK)182return NOTOK;183184if (mergeBlocker != NIL)185{186if (_FindK33WithMergeBlocker(theGraph, context, I, mergeBlocker) != OK)187return NOTOK;188189return NONEMBEDDABLE;190}191}192193/* Each DFS child is listed in DFI order in V[I].sortedDFSChildList.194In V[I].fwdArcList, the forward arcs of all unembedded back edges are195in order by DFI of the descendant endpoint of the edge.196197DFS descendants have a higher DFI than ancestors, so given two198successive children C1 and C2, if any forward arcs lead to a199vertex D such that DFI(C1) < DFI(D) < DFI(C2), then the Walkdown200failed to embed a back edge from I to a descendant D of C1. */201202e = theGraph->V[I].fwdArcList;203D = theGraph->G[e].v;204205C1 = context->V[I].sortedDFSChildList;206207FoundOne = FALSE;208209while (C1 != NIL && e != NIL)210{211C2 = LCGetNext(context->sortedDFSChildLists,212context->V[I].sortedDFSChildList, C1);213214// If the edge e leads from I to a descendant D of C1,215// then D will be less than C2 (as explained above),216// so we search for a K_{3,3} in the bicomp rooted217// by the root copy of I associated with C1.218// (If C2 is NIL, then C1 is the last child)219220if (D < C2 || C2 == NIL)221{222FoundOne = TRUE;223RetVal = _SearchForK33InBicomp(theGraph, context, I, C1+theGraph->N);224225// If something went wrong, NOTOK was returned;226// If a K_{3,3} was found, NONEMBEDDABLE was returned;227// If OK was returned, then only a K5 was found, so228// we continue searching any other bicomps on which229// the Walkdown failed.230231if (RetVal != OK)232break;233}234235// Skip the edges that lead to descendants of C1 to get to those236// edges that lead to descendants of C2.237238if (C2 != NIL)239{240while (D < C2 && gp_IsArc(theGraph, e))241{242e = gp_GetNextArc(theGraph, e);243if (e == theGraph->V[I].fwdArcList)244e = NIL;245else D = theGraph->G[e].v;246}247}248249// Move the DFS child context to C2250C1 = C2;251}252253/* If we got through the loop with an OK value for each bicomp on254which the Walkdown failed, then we return OK to indicate that only255K5's were found (or there is a special case K_{3,3} that may be discovered256later based on a setting we made in the data structure).257The OK return allows the embedder to continue.258259If a K_{3,3} is ever found (or if an error occured), then RetVal260will not be OK, and the loop terminates immediately so we can261return the appropriate value. If a K_{3,3} is found, then we must262also handle the fact that some paths of the input graph may have263been reduced to single edges by prior _ReduceBicomp() calls.264265NOTE: The variable FoundOne helps ensure we detect at least one266bicomp on which the Walkdown failed (this should always be267the case in an error-free implementation like this one!). */268269return FoundOne ? RetVal : NOTOK;270}271272/****************************************************************************273_SearchForK33InBicomp()274****************************************************************************/275276int _SearchForK33InBicomp(graphP theGraph, K33SearchContext *context, int I, int R)277{278isolatorContextP IC = &theGraph->IC;279int tempResult;280281/* Begin by determining which non-planarity minor is detected */282283if (_ChooseTypeOfNonplanarityMinor(theGraph, I, R) != OK)284return NOTOK;285286/* If minor A is selected, then the root of the oriented bicomp has been changed */287288else R = IC->r;289290/* Minors A to D result in the desired K_{3,3} homeomorph,291so we isolate it and return NONEMBEDDABLE. */292293if (theGraph->IC.minorType & (MINORTYPE_A|MINORTYPE_B|MINORTYPE_C|MINORTYPE_D))294{295/* First we restore the orientations of the vertices in the296one bicomp we have messed with so that there is no confusion. */297298if (_OrientVerticesInBicomp(theGraph, R, 1) != OK)299return NOTOK;300301/* Next we restore the orientation of the embedding so we302can restore the reduced paths (because we avoid modifying303the Kuratowski subgraph isolator to restore reduced paths,304which are a construct of the K_{3,3} search). */305306if (_OrientVerticesInEmbedding(theGraph) != OK ||307_RestoreAndOrientReducedPaths(theGraph, context) != OK)308return NOTOK;309310/* Next we simply call the Kuratowski subgraph isolation since311we know now that it will isolate a K_{3,3}.312For minor A, we need to set up the stack that would be313available immediately after a Walkdown failure. */314315if (theGraph->IC.minorType & MINORTYPE_A)316{317sp_ClearStack(theGraph->theStack);318sp_Push2(theGraph->theStack, R, NIL);319}320321if (_IsolateKuratowskiSubgraph(theGraph, I, R) != OK)322return NOTOK;323324return NONEMBEDDABLE;325}326327/* For minor E (a K5 minor), we run the additional tests to see if328minors E1 to E4 apply since these minors isolate a K_{3,3} entangled329with the K5. */330331IC->ux = _GetLeastAncestorConnection(theGraph, IC->x);332IC->uy = _GetLeastAncestorConnection(theGraph, IC->y);333IC->uz = _GetLeastAncestorConnection(theGraph, IC->z);334335if (IC->z != IC->w ||336IC->uz > MAX(IC->ux, IC->uy) ||337(IC->uz < MAX(IC->ux, IC->uy) && IC->ux != IC->uy) ||338(IC->x != IC->px || IC->y != IC->py))339{340if (_OrientVerticesInBicomp(theGraph, R, 1) != OK)341return NOTOK;342343if (_OrientVerticesInEmbedding(theGraph) != OK ||344_RestoreAndOrientReducedPaths(theGraph, context) != OK)345return NOTOK;346347if (_IsolateKuratowskiSubgraph(theGraph, I, R) != OK)348return NOTOK;349350return NONEMBEDDABLE;351}352353/* If the Kuratowski subgraph isolator will not isolate a K_{3,3} based on minor E,354then a K5 homeomorph could be isolated. However, a K_{3,3} may still be tangled355with the K5, so we now run the additional tests of the K_{3,3} search algorithm.356357If the search finds a K_{3,3} (tempResult of NONEMBEDDABLE), then we remove unwanted358edges from the graph and return NONEMBEDDABLE. If the search has a fault (NOTOK),359then we return. If the result is OK, then a K_{3,3} was not found at this time360and we proceed with some clean-up work below. */361362if ((tempResult = _RunExtraK33Tests(theGraph, context)) != OK)363{364if (tempResult == NONEMBEDDABLE)365if (_DeleteUnmarkedVerticesAndEdges(theGraph) != OK)366return NOTOK;367368return tempResult;369}370371/* The extra cases for finding a K_{3,3} did not succeed, so the bicomp rooted by R372is either a K5 homeomorph (with at most a superficially entangled K_{3,3}) or373we have made the special setting that allows us to detect the one case that374would be too costly to try now. Either way, we can safely reduce the bicomp375to the 4-cycle (R, X, W, Y, R) and proceed with the planarity algorithm.376We also restore the mixed orientation of the bicomp (i.e. the proper377orientation in the context of the edge signs) because this code can work378when ReduceBicomp doesn't do any actual work. */379380if (_OrientVerticesInBicomp(theGraph, R, 1) != OK)381return NOTOK;382383if (_ReduceBicomp(theGraph, context, R) != OK)384return NOTOK;385386/* Set visited flags to a high number so planarity algorithm387can properly do Walkup procedure in future steps */388389if (_FillVisitedFlagsInBicomp(theGraph, IC->r, theGraph->N) != OK)390return NOTOK;391392/* We now intend to ignore the pertinence of W (conceptually eliminating393the connection from W to the current vertex). Note that none of the394bicomps listed in the pertinentBicompList (nor their respective subtrees)395will be visited again by the planarity algorithm because they must've396been internally active. If they were externally active and pertinent,397then we would've found a K_{3,3} by non-planarity minor B. Thus, the original398Walkup costs that identified the pertinent bicomps we intend to ignore are399one-time costs, preserving linear time. */400401theGraph->V[IC->w].adjacentTo = NIL;402theGraph->V[IC->w].pertinentBicompList = NIL;403404return OK;405}406407/****************************************************************************408_RunExtraK33Tests()409****************************************************************************/410411int _RunExtraK33Tests(graphP theGraph, K33SearchContext *context)412{413isolatorContextP IC = &theGraph->IC;414int u_max = MAX3(IC->ux, IC->uy, IC->uz), u;415416/* Case 1: If there is a pertinent or externally active vertex other than W417on the lower external face path between X and Y (the points of418attachment of the x-y path), then we can isolate a K_{3,3} homeomorph419by Minor E1. */420421if (_SearchForMinorE1(theGraph) != OK)422return NOTOK;423424if (IC->w != IC->z)425{426if (_FinishIsolatorContextInitialization(theGraph, context) != OK ||427_IsolateMinorE1(theGraph) != OK)428return NOTOK;429430return NONEMBEDDABLE;431}432433/* Case 2: If W/Z can make an external connection to an ancestor of V434that is descendant to u_{max}, then a K_{3,3} homeomorph can435be isolated with Minor E2.436437NOTE: It may seem costly to check the entire subtree, but438if it succeeds then we're done, and if the only connection439is to u_{max} then we are sure to never make this check440again on this subtree (if all the other K_{3,3} tests fail).441442OPTIMIZATION: We do not check for the connection if the443least ancestor connection from W/Z leads to an ancestor444of u_max. The reason is that it could ultimately be too445costly if the connection doesn't exist, and if the highest446numbered ancestor H of the current vertex with an external447connection from W is a descendant u_{max} (and if no other448tests in this function succeed), then we will discover a449K_{3,3} by Minor A or B in step H.450451OPTIMIZATION: When we do test for an external connection to452an ancestor of V descendant to u_{max}, the result may be that453only a connection to u_{max} exists. The result is cached454so that the subtrees of the vertex need not be traversed again455should we need to make the test again.456See _SearchForDescendantExternalConnection() */457458if (IC->uz == u_max)459{460u = _SearchForDescendantExternalConnection(theGraph, context, IC->w, u_max);461if (u > u_max)462{463IC->uz = u;464if (_FinishIsolatorContextInitialization(theGraph, context) != OK ||465_IsolateMinorE2(theGraph) != OK)466return NOTOK;467468return NONEMBEDDABLE;469}470}471472/* Case 3: If X or Y can make an external connection to an ancestor of V473that is descendant to u_{max}, then a K_{3,3} homeomorph474can be isolated with Minor E3.475476NOTE: It may seem costly to check the entire subtree, but477if it succeeds then we're done, and if the only connection478is to u_{max} then we are sure to never make this check479again on this subtree (if all the other K_{3,3} tests fail).480481OPTIMIZATION: Due to the prior use of the Kuratowski subgraph482isolator, we know that at most one of X, Y or W/Z could have an483external connection to an ancestor of u_{max} = MAX(ux, uy, uz).484If it is X or Y, then we do not check for the lower connection485required to find Minor E3 because it might ultimately be too486costly. Instead, we mark the vertex with a 'merge barrier'487of u_{max}. If the planar embedder attempts to merge the vertex488prior to step u_{max}, then the embedder has found the desired489connection and a K_{3,3} is isolated at that time.490491OPTIMIZATION: When we can test for an external connection to492an ancestor of V descendant to u_{max}, the result may be that493only a connection to u_{max} exists. The result is cached494so that the subtrees of the vertex need not be traversed again495should we need to make the test again.496See _SearchForDescendantExternalConnection() */497498if (IC->ux < u_max)499context->V[IC->x].mergeBlocker = u_max;500else501{502u = _SearchForDescendantExternalConnection(theGraph, context, IC->x, u_max);503if (u > u_max)504{505IC->ux = u;506if (_FinishIsolatorContextInitialization(theGraph, context) != OK ||507_IsolateMinorE3(theGraph) != OK)508return NOTOK;509510return NONEMBEDDABLE;511}512}513514if (IC->uy < u_max)515context->V[IC->y].mergeBlocker = u_max;516else517{518u = _SearchForDescendantExternalConnection(theGraph, context, IC->y, u_max);519if (u > u_max)520{521IC->uy = u;522if (_FinishIsolatorContextInitialization(theGraph, context) != OK ||523_IsolateMinorE3(theGraph) != OK)524return NOTOK;525526return NONEMBEDDABLE;527}528}529530/* Case 4: If there exists any x-y path with points of attachment px and py531such that px!=x or py!=y, then a K_{3,3} homeomorph can be isolated532with Minor E4. */533534if (_TestForLowXYPath(theGraph) != OK)535return NOTOK;536537if (IC->px != IC->x || IC->py != IC->y)538{539if (_FinishIsolatorContextInitialization(theGraph, context) != OK ||540_IsolateMinorE4(theGraph) != OK)541return NOTOK;542543return NONEMBEDDABLE;544}545546/* Case 5: If the x-y path contains an internal vertex that starts a second547internal path from the internal vertex to W/Z, then a K_{3,3} homeomorph548can be isolated with Minor E5. */549550if (_TestForZtoWPath(theGraph) != OK)551return NOTOK;552553if (theGraph->G[IC->w].visited)554{555if (_FinishIsolatorContextInitialization(theGraph, context) != OK ||556_IsolateMinorE5(theGraph) != OK)557return NOTOK;558559return NONEMBEDDABLE;560}561562/* Case 6: If uz < u_{max} and there is an external connection (other than external563connections involving X, Y and W/Z) between an ancestor of u_{max} and a564vertex in the range [V...u_{max}), then a K_{3,3} homeomorph can be565isolated with Minor E6.566567OPTIMIZATION: See _TestForStraddlingBridge() */568569if (IC->uz < u_max)570{571if (_TestForStraddlingBridge(theGraph, context, u_max) != NIL)572{573if (_FinishIsolatorContextInitialization(theGraph, context) != OK ||574_IsolateMinorE6(theGraph, context) != OK)575return NOTOK;576577return NONEMBEDDABLE;578}579}580581/* Case 7: If ux < u_{max} or uy < u_{max} and there is an external connection582between an ancestor of u_{max} and a vertex in the range [V...u_{max})583(except for external connections involving X, Y and W/Z), then a K_{3,3}584homeomorph can be isolated with Minor E7.585586OPTIMIZATION: Same as Case 6.*/587588if (IC->ux < u_max || IC->uy < u_max)589{590if (_TestForStraddlingBridge(theGraph, context, u_max) != NIL)591{592if (_FinishIsolatorContextInitialization(theGraph, context) != OK ||593_IsolateMinorE7(theGraph, context) != OK)594return NOTOK;595596return NONEMBEDDABLE;597}598}599600/* If none of the tests found a K_{3,3}, then we return OK to indicate that nothing601went wrong, but a K_{3,3} was not found. */602603return OK;604}605606/****************************************************************************607_SearchForMinorE1()608Search along the external face below the x-y path for a vertex Z other609than W that is externally active or pertinent.610****************************************************************************/611612int _SearchForMinorE1(graphP theGraph)613{614int Z=theGraph->IC.px, ZPrevLink=1;615616Z = _GetNextVertexOnExternalFace(theGraph, Z, &ZPrevLink);617618while (Z != theGraph->IC.py)619{620if (Z != theGraph->IC.w)621{622if (_VertexActiveStatus(theGraph, Z, theGraph->IC.v) == VAS_EXTERNAL)623{624theGraph->IC.z = Z;625theGraph->IC.uz = _GetLeastAncestorConnection(theGraph, Z);626return OK;627}628else if (theGraph->V[Z].pertinentBicompList != NIL ||629theGraph->V[Z].adjacentTo == theGraph->IC.v)630{631/* Swap the roles of W and Z */632633theGraph->IC.z = theGraph->IC.w;634theGraph->IC.w = Z;635636/* If the new W (indicated by Z) was on the path (R, X, old W) then637the new Z (the old W, which has no type mark) is on the path638(X, new W, new Z, Y) so we change the type new Z to being on the639RYW path. Otherwise, the order is (X, new Z, new W, Y), so the640new Z (old W with no type) is type changed to be on the RXW path.*/641642if (theGraph->G[Z].type == VERTEX_LOW_RXW)643theGraph->G[theGraph->IC.z].type = VERTEX_LOW_RYW;644else theGraph->G[theGraph->IC.z].type = VERTEX_LOW_RXW;645646/* For completeness, we change the new W to type unknown */647648theGraph->G[theGraph->IC.w].type = TYPE_UNKNOWN;649650/* The external activity ancestor connection of the new Z must be obtained */651652theGraph->IC.uz = _GetLeastAncestorConnection(theGraph, theGraph->IC.z);653654return OK;655}656}657658Z = _GetNextVertexOnExternalFace(theGraph, Z, &ZPrevLink);659}660661return OK;662}663664/****************************************************************************665_FinishIsolatorContextInitialization()666Once it has been decided that a desired subgraph can be isolated, it667becomes safe to finish the isolator context initialization.668****************************************************************************/669670int _FinishIsolatorContextInitialization(graphP theGraph, K33SearchContext *context)671{672isolatorContextP IC = &theGraph->IC;673674/* Restore the orientation of the bicomp on which we're working, then675perform orientation of all vertices in graph. (An unnecessary but676polite step that simplifies the description of key states of the677data structures). */678679if (_OrientVerticesInBicomp(theGraph, IC->r, 1) != OK)680return NOTOK;681682if (_OrientVerticesInEmbedding(theGraph) != OK)683return NOTOK;684685/* Restore any paths that were reduced to single edges */686687if (_RestoreAndOrientReducedPaths(theGraph, context) != OK)688return NOTOK;689690/* We assume that the current bicomp has been marked appropriately,691but we must now clear the visitation flags of all other bicomps. */692693if (_FillVisitedFlagsInOtherBicomps(theGraph, IC->r, 0) != OK)694return NOTOK;695696/* To complete the normal behavior of _FillVisitedFlags() in the697normal isolator context initialization, we also have to clear698the visited flags on all edges that have not yet been embedded */699700_FillVisitedFlagsInUnembeddedEdges(theGraph, 0);701702/* Now we can find the descendant ends of unembedded back edges based on703the ancestor settings ux, uy and uz. */704705if (_FindExternalConnectionDescendantEndpoint(theGraph, IC->ux, IC->x, &IC->dx) != OK ||706_FindExternalConnectionDescendantEndpoint(theGraph, IC->uy, IC->y, &IC->dy) != OK ||707_FindExternalConnectionDescendantEndpoint(theGraph, IC->uz, IC->z, &IC->dz) != OK)708return NOTOK;709710/* Finally, we obtain the descendant end of an unembedded back edge to711the current vertex. */712713if (_FindUnembeddedEdgeToCurVertex(theGraph, IC->w, &IC->dw) != TRUE)714return NOTOK;715716return OK;717}718719/****************************************************************************720_GetAdjacentAncestorInRange()721Returns the ancestor of theVertex that is adjacent to theVertex by an722unembedded back edge and has a DFI strictly between closerAncestor and723fartherAncestor.724Returns NIL if theVertex has no such neighboring ancestor.725****************************************************************************/726727int _GetAdjacentAncestorInRange(graphP theGraph, K33SearchContext *context, int theVertex,728int closerAncestor, int fartherAncestor)729{730int J = context->V[theVertex].backArcList;731732while (gp_IsArc(theGraph, J))733{734if (theGraph->G[J].v < closerAncestor &&735theGraph->G[J].v > fartherAncestor)736return theGraph->G[J].v;737738J = gp_GetNextArc(theGraph, J);739if (J == context->V[theVertex].backArcList)740J = NIL;741}742return NIL;743}744745/****************************************************************************746_SearchForDescendantExternalConnection()747Search the cutVertex and each subtree rooted by a vertex in the748separatedDFSChildList of the cut vertex for an external connection749to a vertex ancestor to the current vertex V and descendant to u_max.750751The function returns the descendant of u_max found to have an external752connection to the given cut vertex.753754OPTIMIZATION: The subtrees are processed by preorder visitation. If755a vertex is visited and has a lowpoint indicating that it and its756descendants make no external connections, then we prune the subtree,757eliminating the vertex and its descendants from consideration.758Otherwise, if the vertex has an externalConnectionAncestor setting,759which must have been made by a prior invocation of this function,760then we use that setting. If both of these tests fail, then761we examine the vertex and push its children for consideration.762This ensures that this procedure never explores a subtree more than763once during the life of the K_{3,3} search algorithm.764765Note that if a subtree is explored and the desired external connection766descendant to u_{max} is found, then a K_{3,3} will be found, so we only767have to concern ourselves with subtrees that connect only to u_{max}.768Between steps v and u_{max}, the subtree search is optimized by setting769'externalConnectionAncestor', and steps after u_{max} process ancestors770of u_{max}. Since this routine is only called if the cutVertex makes771no external connections to ancestors of u_{max}, the lowpoint test772prevents this subtree from being searched after step u_{max}.773****************************************************************************/774775int _SearchForDescendantExternalConnection(graphP theGraph, K33SearchContext *context, int cutVertex, int u_max)776{777isolatorContextP IC = &theGraph->IC;778int u2 = _GetAdjacentAncestorInRange(theGraph, context, cutVertex, IC->v, u_max);779int listHead, child, descendant;780781/* Test cut vertex for external connection to descendant of u_max */782783if (u2 != NIL)784return u2;785786/* If there is no direct back edge connection from the cut vertex787to a vertex on the path between V and u_max, then we will788look for such a connection in the DFS subtrees rooted by789separated DFS children of the vertex (ignoring those whose790lowpoint indicates that they make no external connections) */791792/* Begin by pushing the separated DFS children of the cut vertex,793except stop when the lowpoint is no longer less than V since794external connections are not being made. */795796sp_ClearStack(theGraph->theStack);797listHead = child = theGraph->V[cutVertex].separatedDFSChildList;798while (child != NIL)799{800if (theGraph->V[child].Lowpoint >= IC->v)801break;802sp_Push(theGraph->theStack, child);803child = LCGetNext(theGraph->DFSChildLists, listHead, child);804}805806/* Now process the stack until it is empty or until we've found the desired connection. */807808while (!sp_IsEmpty(theGraph->theStack))809{810sp_Pop(theGraph->theStack, descendant);811812/* If the vertex has a lowpoint indicating that it makes no external813connections, then skip the subtree rooted by the vertex */814815if (theGraph->V[descendant].Lowpoint < IC->v)816{817/* If a prior invocation has precalculated the result, use it. */818819if (context->V[descendant].externalConnectionAncestor != NIL)820{821/* If the result is in the range we need, return it. Otherwise,822skip the subtree rooted by the vertex. */823824if (context->V[descendant].externalConnectionAncestor < IC->v &&825context->V[descendant].externalConnectionAncestor > u_max)826return context->V[descendant].externalConnectionAncestor;827}828829/* If the subtree has not been explored, then explore it. */830831else832{833/* Check the subtree root for the desired connection. */834835u2 = _GetAdjacentAncestorInRange(theGraph, context, descendant, IC->v, u_max);836if (u2 != NIL)837return u2;838839/* Push each child as a new subtree root to be considered,840except skip those whose lowpoint is too great. */841842child = context->V[descendant].sortedDFSChildList;843while (child != NIL)844{845if (theGraph->V[child].Lowpoint < IC->v)846sp_Push(theGraph->theStack, child);847848child = LCGetNext(context->sortedDFSChildLists,849context->V[descendant].sortedDFSChildList, child);850}851}852}853}854855/* The only external connections from the cutVertex lead to u_max,856so cache the result and return it. */857858context->V[cutVertex].externalConnectionAncestor = u_max;859return u_max;860}861862/****************************************************************************863_FindExternalConnectionDescendantEndpoint()864865This operation is similar to _FindUnembeddedEdgeToAncestor() except that866we need to be more precise in this case, finding an external connection867from a given cut vertex to a *particular* given ancestor.868869NOTE: By external we don't mean externall active so much as not embedded in870the bicomp containing the cut vertex.871872Returns OK if it finds that either the given cutVertex or one of its873descendants in a separated bicomp has an unembedded back edge874connection to the given ancestor vertex.875Returns NOTOK otherwise (it is an error to not find the descendant because876this function is only called if _SearchForDescendantExternalConnection()877has already determined the existence of the descendant).878****************************************************************************/879880int _FindExternalConnectionDescendantEndpoint(graphP theGraph, int ancestor,881int cutVertex, int *pDescendant)882{883int listHead, child, J;884885// Check whether the cutVertex is directly adjacent to the ancestor886// by an unembedded back edge.887888J = theGraph->V[ancestor].fwdArcList;889while (gp_IsArc(theGraph, J))890{891if (theGraph->G[J].v == cutVertex)892{893*pDescendant = cutVertex;894return OK;895}896897J = gp_GetNextArc(theGraph, J);898if (J == theGraph->V[ancestor].fwdArcList)899J = NIL;900}901902// Now check the descendants of the cut vertex to see if any make903// a connection to the ancestor.904listHead = child = theGraph->V[cutVertex].separatedDFSChildList;905while (child != NIL)906{907if (theGraph->V[child].Lowpoint >= theGraph->IC.v)908break;909910if (_FindUnembeddedEdgeToSubtree(theGraph, ancestor, child, pDescendant) == TRUE)911return OK;912913child = LCGetNext(theGraph->DFSChildLists, listHead, child);914}915916return NOTOK;917}918919/****************************************************************************920_SearchForMergeBlocker()921922This function helps to implement the merge blocking optimization of923_SearchForDescendantExternalConnection(). The function RunExtraK33Tests()924sets a mergeBlocker rather than run _SearchForDescendantExternalConnection()925in certain cases. This procedure is called by MergeBicomps to test the926embedding stack for a merge blocker before merging any biconnected components.927If a merge blocker is found, then the embedder's Walkdown function is928terminated and SearchForK33() is subsequently called. The blocked merge929point is then used as the basis for isolating a K_{3,3}.930931Returns OK on success (whether or not the search found a merge blocker)932NOTOK on internal function failure933pMergeBlocker is set to NIL unless a merge blocker is found.934****************************************************************************/935936int _SearchForMergeBlocker(graphP theGraph, K33SearchContext *context, int I, int *pMergeBlocker)937{938stackP tempStack;939int R, Rout, Z, ZPrevLink;940941/* Set return result to 'not found' then return if there is no stack to inspect */942943*pMergeBlocker = NIL;944945if (sp_IsEmpty(theGraph->theStack))946return OK;947948/* Create a copy of the embedding stack */949950tempStack = sp_Duplicate(theGraph->theStack);951if (tempStack == NULL)952return NOTOK;953954/* Search the copy of the embedding stack for a merge blocked vertex */955956while (!sp_IsEmpty(tempStack))957{958sp_Pop2(tempStack, R, Rout);959sp_Pop2(tempStack, Z, ZPrevLink);960961if (context->V[Z].mergeBlocker != NIL &&962context->V[Z].mergeBlocker < I)963{964*pMergeBlocker = Z;965break;966}967}968969sp_Free(&tempStack);970return OK;971}972973/****************************************************************************974_FindK33WithMergeBlocker()975976This function completes the merge blocking optimization by isolating a K_{3,3}977based on minor E3 if a merge blocked vertex was previously found.978979Returns OK on success, NOTOK on internal function failure980****************************************************************************/981982int _FindK33WithMergeBlocker(graphP theGraph, K33SearchContext *context, int I, int mergeBlocker)983{984int R, RPrevLink, u_max, u, J, W;985isolatorContextP IC = &theGraph->IC;986987/* First, we orient the vertices so we can successfully restore all of the988reduced paths. This needs to be done before reconstructing the context989for CASE 3 of RunExtraK33Tests() because the reconstruction involves990using the Walkup to I from a descendant of I, which will not work if991the descendant is in one of the reduced paths. */992993if (_OrientVerticesInEmbedding(theGraph) != OK ||994_RestoreAndOrientReducedPaths(theGraph, context) != OK)995return NOTOK;996997/* Reconstruct the context that was present for CASE 3 of RunExtraK33Tests()998when we decided to set a mergeBlocker rather than calling999_SearchForDescendantExternalConnection() */10001001/* Obtain the root of the bicomp containing the mergeBlocker. */10021003RPrevLink = 1;1004R = mergeBlocker;1005while (R < theGraph->N)1006R = _GetNextVertexOnExternalFace(theGraph, R, &RPrevLink);10071008/* Switch the 'current step' variable I to be equal to the1009non-virtual counterpart of the bicomp root. */10101011I = theGraph->V[R - theGraph->N].DFSParent;10121013/* Eliminate the visitation and pertinence settings for step u_max */10141015_FillVisitedFlags(theGraph, I+1);10161017for (J = 0; J < theGraph->N; J++)1018{1019theGraph->V[J].adjacentTo = NIL;1020theGraph->V[J].pertinentBicompList = NIL;1021}10221023/* Restore the pertinence settings of step I by doing the Walkup for each1024back edge that was not embedded when step I was originally performed. */10251026J = theGraph->V[I].fwdArcList;1027while (gp_IsArc(theGraph, J))1028{1029W = theGraph->G[J].v;1030theGraph->functions.fpWalkUp(theGraph, I, W);10311032J = gp_GetNextArc(theGraph, J);1033if (J == theGraph->V[I].fwdArcList)1034J = NIL;1035}10361037/* Next, we make the standard initialization calls for when we have found1038a non-planarity condition. */10391040sp_ClearStack(theGraph->theStack);10411042if (_ChooseTypeOfNonplanarityMinor(theGraph, I, R) != OK)1043return NOTOK;10441045IC->ux = _GetLeastAncestorConnection(theGraph, IC->x);1046IC->uy = _GetLeastAncestorConnection(theGraph, IC->y);1047IC->uz = _GetLeastAncestorConnection(theGraph, IC->z);10481049u_max = MAX3(IC->ux,IC->uy,IC->uz);10501051/* Perform the remainder of CASE 3 of RunExtraK33Tests() */10521053if (mergeBlocker == IC->x)1054{1055u = _SearchForDescendantExternalConnection(theGraph, context, IC->x, u_max);1056if (u > u_max)1057{1058IC->ux = u;1059if (_FinishIsolatorContextInitialization(theGraph, context) != OK ||1060_IsolateMinorE3(theGraph) != OK)1061return NOTOK;1062}1063else return NOTOK;1064}1065else if (mergeBlocker == IC->y)1066{1067u = _SearchForDescendantExternalConnection(theGraph, context, IC->y, u_max);1068if (u > u_max)1069{1070IC->uy = u;1071if (_FinishIsolatorContextInitialization(theGraph, context) != OK ||1072_IsolateMinorE3(theGraph) != OK)1073return NOTOK;1074}1075else return NOTOK;1076}1077else return NOTOK;10781079/* Do the final clean-up to obtain the K_{3,3} */10801081if (_DeleteUnmarkedVerticesAndEdges(theGraph) != OK)1082return NOTOK;10831084return OK;1085}10861087/****************************************************************************1088_TestForLowXYPath()1089Is there an x-y path that does not include X?1090If not, is there an x-y path that does not include Y?1091If not, then we restore the original x-y path.1092If such a low x-y path exists, then we adjust px or py accordingly,1093and we make sure that X or Y (whichever is excluded) and its edges are1094not marked visited.1095This method uses the stack, though it is called with an empty stack currently,1096it does happen to preserve any preceding stack content. This method pushes1097at most one integer per edge incident to the bicomp root plus two integers1098per vertex in the bicomp.1099****************************************************************************/11001101int _TestForLowXYPath(graphP theGraph)1102{1103isolatorContextP IC = &theGraph->IC;1104int result;1105int stackBottom;11061107/* Clear the previously marked X-Y path */11081109if (_FillVisitedFlagsInBicomp(theGraph, IC->r, 0) != OK)1110return NOTOK;11111112/* Save the size of the stack before hiding any edges, so we will know1113how many edges to restore */11141115stackBottom = sp_GetCurrentSize(theGraph->theStack);11161117/* Hide the internal edges of X */11181119if (_HideInternalEdges(theGraph, IC->x) != OK)1120return NOTOK;11211122/* Try to find a low X-Y path that excludes X, then restore the1123internal edges of X. */11241125result = _MarkHighestXYPath(theGraph);1126if (_RestoreInternalEdges(theGraph, stackBottom) != OK)1127return NOTOK;11281129/* If we found the low X-Y path, then return. */11301131if (result == TRUE)1132return OK;11331134/* Hide the internal edges of Y */11351136if (_HideInternalEdges(theGraph, IC->y) != OK)1137return NOTOK;11381139/* Try to find a low X-Y path that excludes Y, then restore the1140internal edges of Y. */11411142result = _MarkHighestXYPath(theGraph);1143if (_RestoreInternalEdges(theGraph, stackBottom) != OK)1144return NOTOK;11451146/* If we found the low X-Y path, then return. */11471148if (result == TRUE)1149return OK;11501151/* Restore the original X-Y path and return with no error1152(the search failure is reflected by no change to px and py */11531154if (_MarkHighestXYPath(theGraph) != TRUE)1155return NOTOK;11561157return OK;1158}11591160/****************************************************************************1161_TestForZtoWPath()1162This function tests whether there is a path inside the bicomp leading from W1163to some internal node of the x-y path. If there is, the path is marked.11641165Upon function return, the marking of W distinguishes whether the path was found.1166The function returns NOTOK on internal error, OK otherwise.11671168All internal vertices are marked as type unknown, as are W and the bicomp1169root. There is an X-Y path marked visited. So, we start a depth first1170search from W to find a visited vertex, except we prune the search to1171ignore vertices whose type is not unknown.11721173The depth first search has to mark the vertices it has seen as visited,1174but we do not want to conflict with the visited/non-visited settings1175that have so far been used to isolate the X-Y path. So, each vertex1176visited is marked with a NIL and pushed onto the resetList. At the end,1177all vertices on the resetList have their visited flags reset to 0.11781179For each vertex we visit, if it is an internal vertex on the X-Y path1180(i.e. visited=1 and type unknown), then we want to stop and unroll the1181stack to obtain the desired path (described below). If the vertex is type1182unknown, then we want to visit its unvisited neighbors.11831184We want to manage the stack so that it when the desired vertex is found,1185the stack contains the desired path. So, we do not simply push the1186neighbors of the vertex being visited. First, we only push 'eligible'1187vertices (i.e. vertices with a type of unknown and visited not equal to1188NIL). Second, when we decide a vertex v is eligible, we push (v, NIL).1189When we pop (v, NIL), we know that its type is unknown so we test1190whether it is the desired vertex by checking if its visited member is1191equal to 1. If so, then we can stop the depth first search, process1192the resetList, then use the vertices and edges remaining on the1193stack to mark the desired path.11941195If we pop (v, NIL) and find that the visited of v equals 0, then we1196set its visited to NIL. Then we find the first edge record e leading1197to an eligible vertex w (i.e. a vertex with type unknown and visited1198not equal to NIL), and we push both (v, e) and (w, NIL). Eventually all1199paths leading from w will be explored, and if none find the desired vertex,1200then (v, e) is popped. Now we search the adjacency list of v starting1201after e to find the edge record that indicates the next eligible vertex1202to visit. If none are found, then we simply go to the next iteration,1203which pops a 2-tuple containing the vertex u and an edge record e that1204indicates v as the neighbor of u. Finally, if the stack empties without1205finding the desired vertex, then we simply process the resetStack and return.1206****************************************************************************/12071208int _TestForZtoWPath(graphP theGraph)1209{1210isolatorContextP IC = &theGraph->IC;1211stackP resetList = sp_New(_GetBicompSize(theGraph, IC->r));1212int v, e, w;12131214if (resetList == NULL) return NOTOK;12151216sp_ClearStack(theGraph->theStack);1217sp_Push2(theGraph->theStack, IC->w, NIL);12181219while (!sp_IsEmpty(theGraph->theStack))1220{1221sp_Pop2(theGraph->theStack, v, e);12221223if (e == NIL)1224{1225if (theGraph->G[v].visited)1226break;12271228theGraph->G[v].visited = NIL;1229sp_Push(resetList, v);12301231e = gp_GetFirstArc(theGraph, v);1232}1233else1234e = gp_GetNextArc(theGraph, e);12351236while (gp_IsArc(theGraph, e))1237{1238w = theGraph->G[e].v;1239if (theGraph->G[w].visited != NIL &&1240theGraph->G[w].type == TYPE_UNKNOWN)1241{1242sp_Push2(theGraph->theStack, v, e);1243sp_Push2(theGraph->theStack, w, NIL);1244break;1245}1246e = gp_GetNextArc(theGraph, e);1247}1248}12491250while (!sp_IsEmpty(resetList))1251{1252sp_Pop(resetList, v);1253theGraph->G[v].visited = 0;1254}1255sp_Free(&resetList);12561257while (!sp_IsEmpty(theGraph->theStack))1258{1259sp_Pop2(theGraph->theStack, v, e);1260theGraph->G[v].visited = 1;1261theGraph->G[e].visited = 1;1262theGraph->G[gp_GetTwinArc(theGraph, e)].visited = 1;1263}12641265return OK;1266}12671268/****************************************************************************1269_TestForStraddlingBridge()1270We proceed on the path [V...u_{max}) from the current vertex V up to and1271excluding u_{max}. For each vertex p, we test whether p has a least1272ancestor less than u_{max} and whether p has a DFS child c that is not an1273ancestor of X, Y and W and that has a connection to an ancestor of u_{max}1274(in other words, whether the child C has a lowpoint less than u_{max}).12751276The separatedDFSChildList of each vertex already contains a list of1277the DFS children sorted by their lowpoint, and the list has not been1278reduced by bicomp merging because the vertices are not descendants of V.1279So, we can process a vertex by examining its leastAncestor and the1280lowpoint of one of the first two elements in its separatedDFSChildList.1281If the first child is an ancestor of X, Y and W, then we look at the1282second child.12831284If no bridge straddling u_{max} is found, the function returns NIL.1285If a straddling bridge is found, the function returns a descendant d1286of p in the subtree rooted by c such that d has a leastAncestor less1287than u_{max}. Given the vertex d, the path through the straddling1288bridge required in Minors E6 and E7 is easy to identify: Mark the1289DFS tree path from d to p, and add and mark the edge from d to its1290least ancestor.12911292OPTIMIZATION: If a straddling bridge is not found, then in each tree edge of1293the path [V...u_{max}) we set the member noStraddle equal to u_{max}.1294Then, we modify the above stated routine so that if it is testing1295for a straddling bridge of u_{max} along this path, it will stop1296if it encounters an edge with noStraddle equal to u_{max} then it1297will stop. Also, the optimization will only set noStraddle equal to1298u_{max} on the portion of the path that is traversed. Finally, if1299noStraddle is set to a value other than NIL, the setting will be1300ignored and it will not be changed.13011302Due to this optimization, we do not traverse a path more than once1303to find out whether a vertex on the path has a bridge that straddles1304u_{max}. This leaves two questions:13051) What if a future step must determine whether there is a1306straddling bridge of an ancestor of u_{max}?13072) What if a future step must determine whether there is a1308straddling bridge of a descendant of u_{max}?13091310The condition described in the first question cannot occur because it1311would imply the ability to detect a straddling bridge now.1312The condition described by the second question may occur, but in the1313future step, the bicomp now being tested for a K_{3,3} will be part of1314a straddling bridge in that future step. Thus, the straddling1315bridge query is asked at most twice along any DFS tree path.1316****************************************************************************/13171318int _TestForStraddlingBridge(graphP theGraph, K33SearchContext *context, int u_max)1319{1320isolatorContextP IC = &theGraph->IC;1321int p, c, d, excludedChild, e;13221323p = IC->v;1324excludedChild = IC->r - theGraph->N;1325d = NIL;13261327/* Starting at V, traverse the ancestor path to u_max looking for a straddling bridge */13281329while (p > u_max)1330{1331/* If we find a direct edge from p to an ancestor of u_max, the break. */13321333if (theGraph->V[p].leastAncestor < u_max)1334{1335d = p;1336break;1337}13381339/* Check for a path from p to an ancestor of u_max using the child1340of p with the least Lowpoint, except the child that is an1341ancestor of X, Y and W. */13421343c = theGraph->V[p].separatedDFSChildList;1344if (c == excludedChild)1345c = LCGetNext(theGraph->DFSChildLists, c, c);13461347if (c != NIL && theGraph->V[c].Lowpoint < u_max)1348{1349_FindUnembeddedEdgeToSubtree(theGraph, theGraph->V[c].Lowpoint, c, &d);1350break;1351}13521353/* Check for noStraddle of u_max, break if found */13541355e = gp_GetFirstArc(theGraph, p);1356if (context->G[e].noStraddle == u_max)1357break;13581359/* Go to the next ancestor */13601361excludedChild = p;1362p = theGraph->V[p].DFSParent;1363}13641365/* If d is NIL, then no straddling bridge was found, so we do the1366noStraddle optimization. */13671368if (d == NIL)1369{1370c = IC->v;1371while (c != p)1372{1373e = gp_GetFirstArc(theGraph, c);1374if (context->G[e].noStraddle != NIL)1375break;13761377context->G[e].noStraddle = u_max;13781379c = theGraph->V[c].DFSParent;1380}1381}13821383/* Return either NIL indicating no bridge straddling u_max or the descendant d1384used to help mark a straddling bridge that was found by this test. */13851386return d;1387}13881389/****************************************************************************1390_ReduceBicomp()13911392We want to reduce the given biconnected component to a 4-cycle plus an1393internal edge connecting X and Y. Each edge is to be associated with a1394path from the original graph, preserving the depth first search tree1395paths that help connect the vertices R, X, Y, and W. If a K_{3,3} is later found,1396the paths are restored, but it is necessary to preserve the DFS tree so that1397functions like MarkDFSPath() will be able to pass through the restored bicomp.1398Also, if a K_{3,3} is later found due to the merge blocker optimization, then the1399internal X-Y path may be needed and, once the bicomp reduction is reversed,1400a full DFS subtree connecting all vertices in the bicomp will need to be1401restored or else functions that traverse the bicomp will not work.14021403For example, _FindK33WithMergeBlocker() invokes ChooseTypeOfNonplanarityMinor()1404to help reconstruct the context under which the mergeBlocker was set.1405ChooseTypeOfNonplanarityMinor() calls _FillVisitedFlagsInBicomp(), which1406depends on the DFS tree.14071408NOTE: The following are some general steps taken in this method:14091) All edges in the bicomp are marked unvisited14102) selected paths are marked visited14113) unvisited edges are deleted14124) the edges of the bicomp are marked unvisited again14135) the remaining paths of the bicomp are reduced1414Some of the edges that get deleted in step 3 above may represent1415paths that were reduced in prior embedder iterations. We delete1416the reduction edge but not the path it represents.1417If a K_{3,3} is ever found, then the edges of these reduced paths1418are still in the graph, though not connected to anything important.1419The desired K_{3,3} is marked visited, but step 4 above ensures that1420these reduction paths are not marked visited. Hence, they will be1421deleted when the K_{3,3} is isolated, and this routine does not1422need to restore any reduced paths on the edges it deletes.1423We also don't (and don't have the time to) restore any reduction1424edges along the paths we intend to keep.1425****************************************************************************/14261427int _ReduceBicomp(graphP theGraph, K33SearchContext *context, int R)1428{1429isolatorContextP IC = &theGraph->IC;1430int min, mid, max, A, A_edge, B, B_edge;1431int rxType, xwType, wyType, yrType, xyType;14321433/* The vertices in the bicomp need to be oriented so that functions1434like MarkPathAlongBicompExtFace() will work. */14351436if (_OrientVerticesInBicomp(theGraph, R, 0) != OK)1437return NOTOK;14381439/* The reduced edges start with a default type of 'tree' edge. The1440tests below, which identify the additional non-tree paths1441needed to complete the reduced bicomp, also identify which1442reduced edges need to be cycle edges.*/14431444rxType = xwType = wyType = yrType = xyType = EDGE_DFSPARENT;14451446/* Now we calculate some values that help figure out the shape of the1447DFS subtree whose structure will be retained in the bicomp. */14481449min = MIN3(IC->x, IC->y, IC->w);1450max = MAX3(IC->x, IC->y, IC->w);1451mid = MAX3(MIN(IC->x, IC->y), MIN(IC->x, IC->w), MIN(IC->y, IC->w));14521453/* If the order of descendendancy from V goes first to X, then it can1454proceed either to W then Y or to Y then W */14551456if (min == IC->x)1457{1458/* A is a descendant adjacent to the current vertex by a cycle edge1459whose DFS tree path to either mid or max is combined with the1460cycle edge to form the path that will be reduced to the1461external face cycle edge (V, max). */14621463A_edge = gp_GetLastArc(theGraph, IC->r);1464A = theGraph->G[A_edge].v;1465yrType = EDGE_BACK;14661467/* If Y is max, then a path parallel to the X-Y path will be a1468second path reduced to a cycle edge. We find the neighbor B1469of min=X on the X-Y path. The edge (B, min) is a cycle edge1470that, along with the DFS tree path (B, ..., max), will be1471retained and reduced to a cycle edge. */14721473if (max == IC->y)1474{1475B_edge = gp_GetLastArc(theGraph, IC->x);1476while (B_edge != gp_GetFirstArc(theGraph, IC->x))1477{1478if (theGraph->G[B_edge].visited) break;1479B_edge = gp_GetPrevArc(theGraph, B_edge);1480}14811482if (!theGraph->G[B_edge].visited)1483return NOTOK;14841485B = theGraph->G[B_edge].v;1486xyType = EDGE_BACK;1487}14881489/* Otherwise, W is max so we find the neighbor B of min=X on the1490lower external face path (X, ..., W), which excludes V. The1491cycle edge (B, min) and the DFS tree path (B, max) will be1492retained and reduced to a cycle edge.*/14931494else if (max == IC->w)1495{1496B_edge = gp_GetFirstArc(theGraph, IC->x);1497B = theGraph->G[B_edge].v;1498xwType = EDGE_BACK;1499}15001501else return NOTOK;1502}15031504/* Otherwise, the order of descendancy from V goes first to Y, then it1505proceeds to either W then X or to X then W. The */15061507else1508{1509A_edge = gp_GetFirstArc(theGraph, IC->r);1510A = theGraph->G[A_edge].v;1511rxType = EDGE_BACK;15121513if (max == IC->x)1514{1515B_edge = gp_GetFirstArc(theGraph, IC->y);1516while (B_edge != gp_GetLastArc(theGraph, IC->y))1517{1518if (theGraph->G[B_edge].visited) break;1519B_edge = gp_GetNextArc(theGraph, B_edge);1520}15211522if (!theGraph->G[B_edge].visited)1523return NOTOK;15241525B = theGraph->G[B_edge].v;1526xyType = EDGE_BACK;1527}15281529else if (max == IC->w)1530{1531B_edge = gp_GetLastArc(theGraph, IC->y);1532B = theGraph->G[B_edge].v;1533wyType = EDGE_BACK;1534}15351536else return NOTOK;1537}15381539/* Now that we have collected the information on which cycle edge and1540which tree paths will actually be retained, we clear the visited1541flags so the current X-Y path will not be retained (an X-Y path1542formed mostly or entirely from DFS tree edges is retained). */15431544if (_FillVisitedFlagsInBicomp(theGraph, R, 0) != OK)1545return NOTOK;15461547/* Now we mark the tree path from the maximum numbered vertex up1548to the bicomp root. This marks one of the following four paths:1549Case 1. (V, ..., X=min, ..., W=mid, ..., Y=max)1550Case 2. (V, ..., X=min, ..., Y=mid, ..., W=max)1551Case 3. (V, ..., Y=min, ..., W=mid, ..., X=max)1552Case 4. (V, ..., Y=min, ..., X=mid, ..., W=max) */15531554if (theGraph->functions.fpMarkDFSPath(theGraph, R, max) != OK)1555return NOTOK;15561557/* Now we use A to mark a path on the external face corresponding to:1558Case 1. (V, ..., Y=max)1559Case 2. (V, ..., Y=mid)1560Case 3. (V, ..., X=max)1561Case 4. (V, ..., X=mid) */15621563if (theGraph->functions.fpMarkDFSPath(theGraph, min==IC->x ? IC->y : IC->x, A) != OK)1564return NOTOK;15651566theGraph->G[A_edge].visited = 1;1567theGraph->G[gp_GetTwinArc(theGraph, A_edge)].visited = 1;15681569/* Now we use B to mark either an X-Y path or a path of the external face1570corresponding to:1571Case 1. (X=min, ..., B, ..., Y=max)1572Case 2. (X=min, ..., B, ..., W=max)1573Case 3. (Y=min, ..., B, ..., X=max)1574Case 4. (Y=min, ..., B, ..., W=max) */15751576if (theGraph->functions.fpMarkDFSPath(theGraph, max, B) != OK)1577return NOTOK;15781579theGraph->G[B_edge].visited = 1;1580theGraph->G[gp_GetTwinArc(theGraph, B_edge)].visited = 1;15811582/* Delete the unmarked edges in the bicomp. Note that if an unmarked edge1583* represents a reduced path, then only the reduction edge is deleted here.1584* The path it represents is only deleted later (see NOTE above) */15851586if (_DeleteUnmarkedEdgesInBicomp(theGraph, R) != OK)1587return NOTOK;15881589/* Clear all visited flags in the bicomp.1590This is the important "step 4" mentioned in the NOTE above */15911592if (_FillVisitedFlagsInBicomp(theGraph, R, 0) != OK)1593return NOTOK;15941595/* Clear all orientation signs in the bicomp.1596Note that the whole bicomp may not be properly oriented at this point1597because we may have exchanged external face paths for internal1598DFS tree paths. However, the reduced bicomp will be properly1599oriented, and the paths of degree 2 vertices will have their1600orientations fixed if/when reduction edges are restored. */16011602if (_ClearInvertedFlagsInBicomp(theGraph, R) != OK)1603return NOTOK;16041605/* Reduce the paths to single edges.1606Note that although the whole bicomp may not be properly oriented at this1607point (as noted above), the four principal vertices R, X, W and Y still1608are consistently oriented with one another, e.g. R's link[0] indicates1609the external face path toward X that excludes W and Y, and X's link[1]1610indicates that same path. */16111612if (_ReduceExternalFacePathToEdge(theGraph, context, R, IC->x, rxType) != OK ||1613_ReduceExternalFacePathToEdge(theGraph, context, IC->x, IC->w, xwType) != OK ||1614_ReduceExternalFacePathToEdge(theGraph, context, IC->w, IC->y, wyType) != OK ||1615_ReduceExternalFacePathToEdge(theGraph, context, IC->y, R, yrType) != OK)1616return NOTOK;16171618if (_ReduceXYPathToEdge(theGraph, context, IC->x, IC->y, xyType) != OK)1619return NOTOK;16201621/* The core planarity method used vertex visited flags in the Walkup, so we have to1622set the vertex visited flags so the remaining vertices will behave as though they1623are unvisited by Walkup when the embedder moves to the next vertex. */16241625theGraph->G[R].visited =1626theGraph->G[IC->x].visited =1627theGraph->G[IC->y].visited =1628theGraph->G[IC->w].visited = IC->v;16291630return OK;1631}16321633/****************************************************************************1634_ReduceExternalFacePathToEdge()1635****************************************************************************/16361637int _ReduceExternalFacePathToEdge(graphP theGraph, K33SearchContext *context, int u, int x, int edgeType)1638{1639int prevLink, v, w, e;16401641/* If the path is a single edge, then no need for a reduction */16421643prevLink = 1;1644v = _GetNextVertexOnExternalFace(theGraph, u, &prevLink);1645if (v == x)1646{1647theGraph->extFace[u].vertex[0] = x;1648theGraph->extFace[x].vertex[1] = u;1649return OK;1650}16511652/* We have the endpoints u and x of the path, and we just computed the1653first vertex internal to the path and a neighbor of u. Now we1654compute the vertex internal to the path and a neighbor of x. */16551656prevLink = 0;1657w = _GetNextVertexOnExternalFace(theGraph, x, &prevLink);16581659/* Delete the two edges that connect the path to the bicomp.1660If either edge is a reduction edge, then we have to restore1661the path it represents. We can only afford to visit the1662endpoints of the path.1663Note that in the restored path, the edge incident to each1664endpoint of the original path is a newly added edge,1665not a reduction edge. */16661667e = gp_GetFirstArc(theGraph, u);1668if (context->G[e].pathConnector != NIL)1669{1670if (_RestoreReducedPath(theGraph, context, e) != OK)1671return NOTOK;1672e = gp_GetFirstArc(theGraph, u);1673v = theGraph->G[e].v;1674}1675gp_DeleteEdge(theGraph, e, 0);16761677e = gp_GetLastArc(theGraph, x);1678if (context->G[e].pathConnector != NIL)1679{1680if (_RestoreReducedPath(theGraph, context, e) != OK)1681return NOTOK;1682e = gp_GetLastArc(theGraph, x);1683w = theGraph->G[e].v;1684}1685gp_DeleteEdge(theGraph, e, 0);16861687/* Add the reduction edge, then set its path connectors so the original1688path can be recovered and set the edge type so the essential structure1689of the DFS tree can be maintained (The 'Do X to Bicomp' functions1690and functions like MarkDFSPath(0 depend on this). */16911692gp_AddEdge(theGraph, u, 0, x, 1);16931694e = gp_GetFirstArc(theGraph, u);1695context->G[e].pathConnector = v;1696theGraph->G[e].type = _ComputeArcType(theGraph, u, x, edgeType);16971698e = gp_GetLastArc(theGraph, x);1699context->G[e].pathConnector = w;1700theGraph->G[e].type = _ComputeArcType(theGraph, x, u, edgeType);17011702/* Set the external face info */17031704theGraph->extFace[u].vertex[0] = x;1705theGraph->extFace[x].vertex[1] = u;17061707return OK;1708}17091710/****************************************************************************1711_ReduceXYPathToEdge()1712****************************************************************************/17131714int _ReduceXYPathToEdge(graphP theGraph, K33SearchContext *context, int u, int x, int edgeType)1715{1716int e, v, w;17171718e = gp_GetFirstArc(theGraph, u);1719e = gp_GetNextArc(theGraph, e);1720v = theGraph->G[e].v;17211722/* If the XY-path is a single edge, then no reduction is needed */17231724if (v == x)1725return OK;17261727/* Otherwise, remove the two edges that join the XY-path to the bicomp */17281729if (context->G[e].pathConnector != NIL)1730{1731if (_RestoreReducedPath(theGraph, context, e) != OK)1732return NOTOK;1733e = gp_GetFirstArc(theGraph, u);1734e = gp_GetNextArc(theGraph, e);1735v = theGraph->G[e].v;1736}1737gp_DeleteEdge(theGraph, e, 0);17381739e = gp_GetFirstArc(theGraph, x);1740e = gp_GetNextArc(theGraph, e);1741w = theGraph->G[e].v;1742if (context->G[e].pathConnector != NIL)1743{1744if (_RestoreReducedPath(theGraph, context, e) != OK)1745return NOTOK;1746e = gp_GetFirstArc(theGraph, x);1747e = gp_GetNextArc(theGraph, e);1748w = theGraph->G[e].v;1749}1750gp_DeleteEdge(theGraph, e, 0);17511752/* Now add a single edge to represent the XY-path */1753gp_InsertEdge(theGraph, u, gp_GetFirstArc(theGraph, u), 0,1754x, gp_GetFirstArc(theGraph, x), 0);17551756/* Now set up the path connectors so the original XY-path can be recovered if needed.1757Also, set the reduction edge's type to preserve the DFS tree structure */17581759e = gp_GetFirstArc(theGraph, u);1760e = gp_GetNextArc(theGraph, e);1761context->G[e].pathConnector = v;1762theGraph->G[e].type = _ComputeArcType(theGraph, u, x, edgeType);17631764e = gp_GetFirstArc(theGraph, x);1765e = gp_GetNextArc(theGraph, e);1766context->G[e].pathConnector = w;1767theGraph->G[e].type = _ComputeArcType(theGraph, x, u, edgeType);17681769return OK;1770}17711772/****************************************************************************1773_RestoreReducedPath()1774Given an edge record of an edge used to reduce a path, we want to restore1775the path in constant time.1776The path may contain more reduction edges internally, but we do not1777search for and process those since it would violate the constant time1778bound required of this function.1779return OK on success, NOTOK on failure1780****************************************************************************/17811782int _RestoreReducedPath(graphP theGraph, K33SearchContext *context, int J)1783{1784int JTwin, u, v, w, x;1785int J0, J1, JTwin0, JTwin1;17861787if (context->G[J].pathConnector == NIL)1788return OK;17891790JTwin = gp_GetTwinArc(theGraph, J);17911792u = theGraph->G[JTwin].v;1793v = context->G[J].pathConnector;1794w = context->G[JTwin].pathConnector;1795x = theGraph->G[J].v;17961797/* Get the locations of the graph nodes between which the new1798graph nodes must be added in order to reconnect the path1799parallel to the edge. */18001801J0 = gp_GetNextArc(theGraph, J);1802J1 = gp_GetPrevArc(theGraph, J);1803JTwin0 = gp_GetNextArc(theGraph, JTwin);1804JTwin1 = gp_GetPrevArc(theGraph, JTwin);18051806/* We first delete the edge represented by J and JTwin. We do so before1807restoring the path to ensure we do not exceed the maximum arc capacity. */18081809gp_DeleteEdge(theGraph, J, 0);18101811/* Now we add the two edges to reconnect the reduced path represented1812by the edge [J, JTwin]. The edge record in u is added between J0 and J1.1813Likewise, the new edge record in x is added between JTwin0 and JTwin1. */18141815if (gp_IsArc(theGraph, J0))1816{1817if (gp_InsertEdge(theGraph, u, J0, 1, v, gp_AdjacencyListEndMark(v), 0) != OK)1818return NOTOK;1819}1820else1821{1822if (gp_InsertEdge(theGraph, u, J1, 0, v, gp_AdjacencyListEndMark(v), 0) != OK)1823return NOTOK;1824}18251826if (gp_IsArc(theGraph, JTwin0))1827{1828if (gp_InsertEdge(theGraph, x, JTwin0, 1, w, gp_AdjacencyListEndMark(w), 0) != OK)1829return NOTOK;1830}1831else1832{1833if (gp_InsertEdge(theGraph, x, JTwin1, 0, w, gp_AdjacencyListEndMark(w), 0) != OK)1834return NOTOK;1835}18361837// Set the types of the newly added edges. In both cases, the first of the two1838// vertex parameters is known to be degree 2 because they are internal to the1839// path being restored, so this operation is constant time.1840if (_SetEdgeType(theGraph, v, u) != OK ||1841_SetEdgeType(theGraph, w, x) != OK)1842return NOTOK;18431844return OK;1845}18461847/****************************************************************************1848_RestoreAndOrientReducedPaths()1849This function searches the embedding for any edges that are specially marked1850as being representative of a path that was previously reduced to a1851single edge by _ReduceBicomp(). The edge is replaced by the path.1852Note that the new path may contain more reduction edges, and these will be1853iteratively expanded by the outer for loop.18541855If the edge records of an edge being expanded are the first or last arcs1856of the edge's vertex endpoints, then the edge may be along the external face.1857If so, then the vertices along the path being restored must be given a1858consistent orientation with the endpoints. It is expected that the embedding1859will have been oriented prior to this operation.1860****************************************************************************/18611862int _RestoreAndOrientReducedPaths(graphP theGraph, K33SearchContext *context)1863{1864int e, J, JTwin, u, v, w, x, visited;1865int J0, JTwin0, J1, JTwin1;18661867for (e = 0; e < theGraph->M + sp_GetCurrentSize(theGraph->edgeHoles);)1868{1869J = theGraph->edgeOffset + 2*e;1870if (context->G[J].pathConnector != NIL)1871{1872visited = theGraph->G[J].visited;18731874JTwin = gp_GetTwinArc(theGraph, J);1875u = theGraph->G[JTwin].v;1876v = context->G[J].pathConnector;1877w = context->G[JTwin].pathConnector;1878x = theGraph->G[J].v;18791880/* Now we need the predecessor and successor edge records1881of J and JTwin. The edge (u, v) will be inserted so1882that the record in u's adjacency list that indicates v1883will be between J0 and J1. Likewise, the edge record1884(x -> w) will be placed between JTwin0 and JTwin1. */18851886J0 = gp_GetNextArc(theGraph, J);1887J1 = gp_GetPrevArc(theGraph, J);1888JTwin0 = gp_GetNextArc(theGraph, JTwin);1889JTwin1 = gp_GetPrevArc(theGraph, JTwin);18901891/* We first delete the edge represented by J and JTwin. We do so before1892restoring the path to ensure we do not exceed the maximum arc capacity. */18931894gp_DeleteEdge(theGraph, J, 0);18951896/* Now we add the two edges to reconnect the reduced path represented1897by the edge [J, JTwin]. The edge record in u is added between J0 and J1.1898Likewise, the new edge record in x is added between JTwin0 and JTwin1. */18991900if (gp_IsArc(theGraph, J0))1901{1902if (gp_InsertEdge(theGraph, u, J0, 1, v, gp_AdjacencyListEndMark(v), 0) != OK)1903return NOTOK;1904}1905else1906{1907if (gp_InsertEdge(theGraph, u, J1, 0, v, gp_AdjacencyListEndMark(v), 0) != OK)1908return NOTOK;1909}19101911if (gp_IsArc(theGraph, JTwin0))1912{1913if (gp_InsertEdge(theGraph, x, JTwin0, 1, w, gp_AdjacencyListEndMark(w), 0) != OK)1914return NOTOK;1915}1916else1917{1918if (gp_InsertEdge(theGraph, x, JTwin1, 0, w, gp_AdjacencyListEndMark(w), 0) != OK)1919return NOTOK;1920}19211922/* Set the types of the newly added edges */19231924if (_SetEdgeType(theGraph, u, v) != OK ||1925_SetEdgeType(theGraph, w, x) != OK)1926return NOTOK;19271928/* We determine whether the reduction edge may be on the external face,1929in which case we will need to ensure that the vertices on the path1930being restored are consistently oriented. This will accommodate1931future invocations of MarkPathAlongBicompExtFace().1932Note: If J0, J1, JTwin0 or JTwin1 is not an edge, then it is1933because we've walked off the end of the edge record list,1934which happens when J and JTwin are either the first or1935last edge of the containing vertex. In turn, the first1936and last edges of a vertex are the ones that hold it onto1937the external face, if it is on the external face. */19381939if ((!gp_IsArc(theGraph, J0) && !gp_IsArc(theGraph, JTwin1)) ||1940(!gp_IsArc(theGraph, J1) && !gp_IsArc(theGraph, JTwin0)))1941{1942if (_OrientExternalFacePath(theGraph, u, v, w, x) != OK)1943return NOTOK;1944}19451946/* The internal XY path was already marked as part of the decision logic1947that made us decide we could find a K_{3,3} and hence that we should1948reverse all of the reductions. Subsequent code counts on the fact1949that the X-Y path is already marked, so if we replace a marked edge1950with a path, then we need to mark the path. Similarly, for an unmarked1951edge, the replacement path should be unmarked. */19521953if (_SetVisitedOnPath(theGraph, u, v, w, x, visited) != OK)1954return NOTOK;1955}1956else e++;1957}19581959return OK;1960}19611962/****************************************************************************1963_MarkStraddlingBridgePath()1964****************************************************************************/19651966int _MarkStraddlingBridgePath(graphP theGraph, int u_min, int u_max, int u_d, int d)1967{1968isolatorContextP IC = &theGraph->IC;1969int p, J;19701971/* Find the point of intersection p between the path (v ... u_max)1972and the path (d ... u_max). */19731974if (theGraph->functions.fpMarkDFSPath(theGraph, u_max, IC->r) != OK)1975return NOTOK;19761977p = d;1978while (!theGraph->G[p].visited)1979{1980theGraph->G[p].visited = 1;19811982J = gp_GetFirstArc(theGraph, p);1983while (gp_IsArc(theGraph, J))1984{1985if (theGraph->G[J].type == EDGE_DFSPARENT)1986break;19871988J = gp_GetNextArc(theGraph, J);1989}19901991theGraph->G[J].visited = 1;1992theGraph->G[gp_GetTwinArc(theGraph, J)].visited = 1;19931994p = theGraph->G[J].v;19951996/* If p is a root copy, mark it visited and skip to the parent copy */1997if (p >= theGraph->N)1998{1999theGraph->G[p].visited = 1;2000p = theGraph->V[p-theGraph->N].DFSParent;2001}2002}20032004/* Unmark the path (p ... u_max), which was marked to help find p.2005The path from v to u_{max} is not needed to form a K_{3,3} except2006for the portion of the path up to p that, with the straddling2007bridge path, comprises part of the connection to u_d. In the2008minor, the path between v and p is edge contracted. */20092010while (p != u_max)2011{2012J = gp_GetFirstArc(theGraph, p);2013while (gp_IsArc(theGraph, J))2014{2015if (theGraph->G[J].type == EDGE_DFSPARENT)2016break;20172018J = gp_GetNextArc(theGraph, J);2019}20202021theGraph->G[J].visited = 0;2022theGraph->G[gp_GetTwinArc(theGraph, J)].visited = 0;20232024p = theGraph->G[J].v;2025theGraph->G[p].visited = 0;20262027/* If p is a root copy, clear its visited flag and skip to the2028parent copy */20292030if (p >= theGraph->N)2031{2032p = theGraph->V[p-theGraph->N].DFSParent;2033theGraph->G[p].visited = 0;2034}2035}20362037/* The straddling bridge must join the path (u_max ... u_min). If u_d is an2038ancestor of u_min, then mark the path that joins u_d to u_min. */20392040if (u_d < u_min)2041if (theGraph->functions.fpMarkDFSPath(theGraph, u_d, u_min) != OK)2042return NOTOK;20432044return OK;2045}20462047/****************************************************************************2048_IsolateMinorE5()2049The paths (x, w), (y, w) and (v, u_{max}) are not needed.2050The x-y path and the internal w-z path are already marked.2051****************************************************************************/20522053int _IsolateMinorE5(graphP theGraph)2054{2055isolatorContextP IC = &theGraph->IC;20562057if (_MarkPathAlongBicompExtFace(theGraph, IC->r, IC->x) != OK ||2058_MarkPathAlongBicompExtFace(theGraph, IC->y, IC->r) != OK ||2059theGraph->functions.fpMarkDFSPath(theGraph, MIN3(IC->ux,IC->uy,IC->uz),2060MAX3(IC->ux,IC->uy,IC->uz)) != OK ||2061_MarkDFSPathsToDescendants(theGraph) != OK ||2062_JoinBicomps(theGraph) != OK ||2063_AddAndMarkUnembeddedEdges(theGraph) != OK)2064return NOTOK;20652066return OK;2067}20682069/****************************************************************************2070_IsolateMinorE6()2071The paths (x, y), (v, w) and (v, u_{max}) are not needed.2072The path through the straddling bridge that connects from an ancestor of2073u_{max} to v is required, but it may connnect to an ancestor p of v.2074In such a case, the path (v, p) is required, while (p, u_{max}) is not.2075****************************************************************************/20762077int _IsolateMinorE6(graphP theGraph, K33SearchContext *context)2078{2079isolatorContextP IC = &theGraph->IC;2080int u_min, u_max, d, u_d;20812082/* Clear the previously marked x-y path */20832084if (_FillVisitedFlagsInBicomp(theGraph, IC->r, 0) != OK)2085return NOTOK;20862087/* Clear dw to stop the marking of path (v, w) */20882089IC->dw = NIL;20902091/* Mark (v, ..., x, ..., w, ..., y, ... v) */20922093if (_MarkPathAlongBicompExtFace(theGraph, IC->r, IC->r) != OK)2094return NOTOK;20952096/* Mark the path through the straddling bridge (except for the final2097edge (u_d, d) which is added last by convention). */20982099u_min = MIN3(IC->ux,IC->uy,IC->uz);2100u_max = MAX3(IC->ux,IC->uy,IC->uz);2101d = _TestForStraddlingBridge(theGraph, context, u_max);2102u_d = theGraph->V[d].leastAncestor;21032104if (_MarkStraddlingBridgePath(theGraph, u_min, u_max, u_d, d) != OK)2105return NOTOK;21062107/* Make the final markings and edge additions */21082109if (theGraph->functions.fpMarkDFSPath(theGraph, u_min, u_max) != OK ||2110_MarkDFSPathsToDescendants(theGraph) != OK ||2111_JoinBicomps(theGraph) != OK ||2112_AddAndMarkUnembeddedEdges(theGraph) != OK ||2113_AddAndMarkEdge(theGraph, u_d, d) != OK)2114return NOTOK;21152116return OK;2117}21182119/****************************************************************************2120_IsolateMinorE7()2121****************************************************************************/21222123int _IsolateMinorE7(graphP theGraph, K33SearchContext *context)2124{2125isolatorContextP IC = &theGraph->IC;2126int u_min, u_max, d, u_d;21272128/* Mark the appropriate two portions of the external face depending on2129symmetry condition */21302131if (IC->uy < IC->ux)2132{2133if (_MarkPathAlongBicompExtFace(theGraph, IC->r, IC->x) != OK ||2134_MarkPathAlongBicompExtFace(theGraph, IC->w, IC->y) != OK)2135return NOTOK;2136}2137else2138{2139if (_MarkPathAlongBicompExtFace(theGraph, IC->x, IC->w) != OK ||2140_MarkPathAlongBicompExtFace(theGraph, IC->y, IC->r) != OK)2141return NOTOK;2142}21432144/* Mark the path through the straddling bridge (except for the final2145edge (u_d, d) which is added last by convention). */21462147u_min = MIN3(IC->ux,IC->uy,IC->uz);2148u_max = MAX3(IC->ux,IC->uy,IC->uz);2149d = _TestForStraddlingBridge(theGraph, context, u_max);2150u_d = theGraph->V[d].leastAncestor;21512152if (_MarkStraddlingBridgePath(theGraph, u_min, u_max, u_d, d) != OK)2153return NOTOK;21542155/* Make the final markings and edge additions */21562157if (theGraph->functions.fpMarkDFSPath(theGraph, u_min, u_max) != OK ||2158_MarkDFSPathsToDescendants(theGraph) != OK ||2159_JoinBicomps(theGraph) != OK ||2160_AddAndMarkUnembeddedEdges(theGraph) != OK ||2161_AddAndMarkEdge(theGraph, u_d, d) != OK)2162return NOTOK;21632164return OK;2165}216621672168