graphTests.c

Go to the documentation of this file.
00001 /* Copyright (c) 2005 by John M. Boyer, All Rights Reserved.  Please see
00002  * License.txt for use and redistribution license. */
00003 /* Copyright (c) 1997-2003 by John M. Boyer, All Rights Reserved.
00004         This code may not be reproduced or disseminated in whole or in part 
00005         without the written permission of the author. */
00006 
00007 #define GRAPHTEST_C
00008 
00009 #include "graph_boyer.h"
00010 #include "stack.h"
00011 
00012 /* Private function declarations */
00013 int _TestPath (graphP theGraph,
00014                int U,
00015                int V);
00016 int _TryPath (graphP theGraph,
00017               int J,
00018               int V);
00019 void _MarkPath (graphP theGraph,
00020                 int J);
00021 int _TestSubgraph (graphP theSubgraph,
00022                    graphP theGraph);
00023 
00024 /********************************************************************
00025  gp_CheckEmbeddingIntegrity()
00026 
00027  This function traverses all faces of a graph structure containing
00028  the planar embedding that results from gp_Embed().  The algorithm
00029  begins by placing all of the graph's arcs onto a stack and marking
00030  all of them as unvisited.  For each arc popped, if it is visited,
00031  it is immediately discarded and the next arc is popped.  Popping an
00032  unvisited arc J begins a face traversal.  We move to the true twin
00033  arc K of J, and obtain its link[0] successor arc L.  This amounts to
00034  always going clockwise or counterclockwise (depending on how the
00035  graph is drawn on the plane, or alternately whether one is above
00036  or below the plane).  This traversal continues until we make it
00037  back to J.  Each arc along the way is marked as visited.  Further,
00038  if L has been visited, then there is an error since an arc can only
00039  appear in one face (the twin arc appears in a separate face, which
00040  is traversed in the opposing direction).
00041  If this algorithm succeeds without double visiting any arcs, and it
00042  produces the correct face count according to Euler's formula, then
00043  the embedding has all vertices oriented the same way.
00044  NOTE:  Because a vertex is in its adj. list, if we go to a link[0]
00045         and it is a vertex, we simply take the vertex's link[0].
00046  NOTE:  In disconnected graphs, the face reader counts the external
00047         face of each connected component.  So, we adjust the face
00048         count by subtracting one for each component, then we add one
00049         to count the external face shared by all components.
00050  ********************************************************************/
00051 int gp_CheckEmbeddingIntegrity (graphP theEmbedding)
00052 {
00053   stackP theStack = theEmbedding->theStack;
00054   int I,
00055     e,
00056     J,
00057     JTwin,
00058     K,
00059     L,
00060     NumFaces,
00061     connectedComponents;
00062   if (theEmbedding == NULL)
00063     return NOTOK;
00064 
00065 /* The stack need only contain 2M entries, one for each edge record. With
00066         max M at 3N, this amounts to 6N integers of space.  The embedding
00067         structure already contains this stack, so we just make sure it
00068         starts out empty. */
00069   sp_ClearStack (theStack);
00070 
00071 /* Push all arcs and set them to unvisited */
00072   for (e = 0, J = 2 * theEmbedding->N; e < theEmbedding->M; e++, J += 2)
00073 
00074   {
00075     sp_Push (theStack, J);
00076     theEmbedding->G[J].visited = 0;
00077     JTwin = gp_GetTwinArc (theEmbedding, J);
00078     sp_Push (theStack, JTwin);
00079     theEmbedding->G[JTwin].visited = 0;
00080   }
00081 
00082 /* Read faces until every arc is used */
00083   NumFaces = 0;
00084   while (sp_NonEmpty (theStack))
00085 
00086   {
00087 
00088     /* Get an arc; if it has already been used by a face, then
00089      * don't use it to traverse a new face */
00090     sp_Pop (theStack, J);
00091     if (theEmbedding->G[J].visited)
00092       continue;
00093     L = NIL;
00094     JTwin = J;
00095     while (L != J)
00096 
00097     {
00098       K = gp_GetTwinArc (theEmbedding, JTwin);
00099       L = theEmbedding->G[K].link[0];
00100       if (L < 2 * theEmbedding->N)
00101         L = theEmbedding->G[L].link[0];
00102       if (theEmbedding->G[L].visited)
00103         return NOTOK;
00104       theEmbedding->G[L].visited++;
00105       JTwin = L;
00106     }
00107     NumFaces++;
00108   }
00109 
00110 /* Count the external face once rather than once per connected component;
00111     each connected component is detected by the fact that it has no
00112     DFS parent, except in the case of isolated vertices, no face was counted
00113     so we do not subtract one. */
00114   for (I = connectedComponents = 0; I < theEmbedding->N; I++)
00115     if (theEmbedding->V[I].DFSParent == NIL)
00116 
00117     {
00118       if (gp_GetVertexDegree (theEmbedding, I) > 0)
00119         NumFaces--;
00120       connectedComponents++;
00121     }
00122   NumFaces++;
00123 
00124 /* Test number of faces using the extended Euler's formula.
00125      For connected components, Euler's formula is f=m-n+2, but
00126      for disconnected graphs it is extended to f=m-n+1+c where
00127      c is the number of connected components.*/
00128   return NumFaces ==
00129     theEmbedding->M - theEmbedding->N + 1 + connectedComponents ? OK : NOTOK;
00130 }
00131 
00132 
00133 /********************************************************************
00134  gp_CheckKuratowskiSubgraphIntegrity()
00135 
00136  This function checks whether theGraph received as input contains
00137  either a K_5 or K_{3,3} homeomorph.
00138 
00139  To be a K_5 homeomorph, there must be exactly 5 vertices of degree 4,
00140  which are called 'image' vertices, and all other vertices must be
00141  either degree 2 or degree 0. Furthermore, each of the image vertices
00142  must be able to reach all of the other image vertices by a single edge
00143  or a path of degree two vertices.
00144 
00145  To be a K_{3,3} homeomorph, there must be exactly 6 vertices of degree 3,
00146  which are called 'image' vertices, and all other vertices must be either
00147  degree 2 or degree 0.  Furthermore, the image vertices must be connected
00148  by edges or paths of degree two vertices in the manner suggested by
00149  a K_{3,3}.  To test this, we select an image vertex U, and determine
00150  three image vertices X, Y and Z reachable from U by single edges or
00151  paths of degree 2 vertices.  Then, we check that the two remaining image
00152  vertices, V and W, can also reach X, Y and Z by single edges or paths of
00153  degree 2 vertices.
00154 
00155  It is not necessary to check that the paths between the image vertices
00156  are distinct since if the paths had a common vertex, then the common
00157  vertex would not be degree 2.
00158  ********************************************************************/
00159 int gp_CheckKuratowskiSubgraphIntegrity (graphP theGraph)
00160 {
00161   int degrees[5],
00162     imageVerts[6];
00163   int I,
00164     degree,
00165     imageVertPos,
00166     temp,
00167     success;
00168 
00169 /* Is theGraph even a subgraph of the original graph? */
00170 
00171 //     if (_TestSubgraph(theGraph, origGraph) != OK)
00172 //         return NOTOK;
00173 
00174 /* Init the variables that count the number of verts of each degree
00175         and the location of each image vert. */
00176   for (I = 0; I < 5; I++)
00177     degrees[I] = 0;
00178   for (I = 0; I < 6; I++)
00179     imageVerts[I] = NIL;
00180   imageVertPos = 0;
00181 
00182 /* Count the number of verts of each degree and find the locations of
00183         the image verts.  Quit if any vertex of degree higher than 4
00184         or equal to 1 is encountered. */
00185   for (I = 0; I < theGraph->N; I++)
00186 
00187   {
00188     degree = gp_GetVertexDegree (theGraph, I);
00189     if (degree == 1 || degree > 4)
00190       return NOTOK;
00191     degrees[degree]++;
00192     if (imageVertPos < 6 && degree > 2)
00193       imageVerts[imageVertPos++] = I;
00194   }
00195 
00196 /* If there are five vertices of degree 4 (and no degree 3 vertices),
00197         then test for a K_5 */
00198   if (degrees[4] == 5 && degrees[3] == 0)
00199 
00200   {
00201     for (I = 0; I < theGraph->N; I++)
00202       theGraph->G[I].visited = 0;
00203     for (imageVertPos = 0; imageVertPos < 5; imageVertPos++)
00204       for (I = 0; I < 5; I++)
00205         if (imageVertPos != I)
00206           if (_TestPath (theGraph, imageVerts[imageVertPos], imageVerts[I]) !=
00207               OK)
00208             return NOTOK;
00209     for (I = 0; I < theGraph->N; I++)
00210       if (theGraph->G[I].visited)
00211         degrees[2]--;
00212 
00213     /* If every degree 2 vertex is used in a path between image
00214      * vertices, then there are no extra pieces of the graph
00215      * in theGraph.  Specifically, the prior tests identify
00216      * a K_5 and ensure that nothing else could exist in the
00217      * graph except extra degree 2 vertices, which must be
00218      * joined in a cycle so that all are degree 2. */
00219     return degrees[2] == 0 ? OK : NOTOK;
00220   }
00221 
00222 /* Otherwise, if there are six vertices of degree 3 (and no degree 4 vertices),
00223         then test for a K_{3,3} */
00224 
00225   else if (degrees[3] == 6 && degrees[4] == 0)
00226 
00227   {
00228 
00229     /* Partition the six image vertices into two sets of 3
00230      * (or report failure) */
00231     for (imageVertPos = 3; imageVertPos < 6; imageVertPos++)
00232 
00233     {
00234       I = success = 0;
00235 
00236       do
00237 
00238       {
00239         if (_TestPath (theGraph, imageVerts[imageVertPos], imageVerts[0]) == OK)
00240 
00241         {
00242           success = 1;
00243           break;
00244         }
00245         I++;
00246         temp = imageVerts[I];
00247         imageVerts[I] = imageVerts[imageVertPos];
00248         imageVerts[imageVertPos] = temp;
00249       } while (I < 3);
00250       if (!success)
00251         return NOTOK;
00252     }
00253 
00254     /* Now test the paths between each of the first three vertices and
00255      * each of the last three vertices */
00256     for (I = 0; I < theGraph->N; I++)
00257       theGraph->G[I].visited = 0;
00258     for (imageVertPos = 0; imageVertPos < 3; imageVertPos++)
00259       for (I = 3; I < 6; I++)
00260         if (_TestPath (theGraph, imageVerts[imageVertPos], imageVerts[I]) != OK)
00261           return NOTOK;
00262     for (I = 0; I < theGraph->N; I++)
00263       if (theGraph->G[I].visited)
00264         degrees[2]--;
00265 
00266     /* If every degree 2 vertex is used in a path between image
00267      * vertices, then there are no extra pieces of the graph
00268      * in theGraph.  Specifically, the prior tests identify
00269      * a K_{3,3} and ensure that nothing else could exist in the
00270      * graph except extra degree 2 vertices, which must be
00271      * joined in a cycle so that all are degree 2. */
00272     return degrees[2] == 0 ? OK : NOTOK;
00273   }
00274 
00275 /* We get here only if we failed to recognize a Kuratowski subgraph, so
00276         we return failure */
00277   return NOTOK;
00278 }
00279 
00280 
00281 /********************************************************************
00282  _TestPath()
00283 
00284  This function determines whether there exists a path of degree two
00285  vertices between two given vertices.  The function marks each
00286  degree two vertex as visited.  It returns NOTOK if it cannot find
00287  such a path.
00288  ********************************************************************/
00289 int _TestPath (graphP theGraph,
00290                int U,
00291                int V)
00292 {
00293   int J;
00294   J = theGraph->G[U].link[0];
00295   while (J > theGraph->N)
00296 
00297   {
00298     if (_TryPath (theGraph, J, V) == OK)
00299 
00300     {
00301       _MarkPath (theGraph, J);
00302       return OK;
00303     }
00304     J = theGraph->G[J].link[0];
00305   }
00306   return NOTOK;
00307 }
00308 
00309 
00310 /********************************************************************
00311  _TryPath()
00312 
00313  This function seeks a given path to a vertex V starting with a
00314  given edge out of a starting vertex U.  The path is allowed to
00315  contain zero or more degree two vertices, but we stop as soon as
00316  a vertex of degree higher than two is encountered.
00317  The function returns OK if that vertex is V, and NOTOK otherwise.
00318  ********************************************************************/
00319 int _TryPath (graphP theGraph,
00320               int J,
00321               int V)
00322 {
00323   int Jin,
00324     nextVertex;
00325   nextVertex = theGraph->G[J].v;
00326   while (gp_GetVertexDegree (theGraph, nextVertex) == 2)
00327 
00328   {
00329     Jin = gp_GetTwinArc (theGraph, J);
00330     J = theGraph->G[nextVertex].link[0];
00331     if (J == Jin)
00332       J = theGraph->G[nextVertex].link[1];
00333     nextVertex = theGraph->G[J].v;
00334   }
00335   return nextVertex == V ? OK : NOTOK;
00336 }
00337 
00338 
00339 /********************************************************************
00340  _MarkPath()
00341 
00342  This function sets the visitation flag on all degree two vertices
00343  along a path to a vertex V that starts with a given edge out of
00344  a starting vertex U.
00345  ********************************************************************/
00346 void _MarkPath (graphP theGraph,
00347                 int J)
00348 {
00349   int Jin,
00350     nextVertex;
00351   nextVertex = theGraph->G[J].v;
00352   while (gp_GetVertexDegree (theGraph, nextVertex) == 2)
00353 
00354   {
00355     theGraph->G[nextVertex].visited = 1;
00356     Jin = gp_GetTwinArc (theGraph, J);
00357     J = theGraph->G[nextVertex].link[0];
00358     if (J == Jin)
00359       J = theGraph->G[nextVertex].link[1];
00360     nextVertex = theGraph->G[J].v;
00361   }
00362 }
00363 
00364 
00365 /********************************************************************
00366  _TestSubgraph()
00367  Checks whether theSubgraph is in face a subgraph of theGraph.
00368  For each vertex v in graph G and subgraph H, we iterate the adjacency
00369  list of H(v) and, for each neighbor w, we mark G(w).  Then, we
00370  iterate the adjacency list of G(v) and unmark each neighbor.  Then,
00371  we iterate the adjacency list of H(v) again to ensure that every
00372  neighbor w was unmarked.  If there exists a marked neighbor, then
00373  H(v) contains an incident edge that is not incident to G(v).
00374 
00375  Returns OK if theSubgraph contains only edges from theGraph,
00376          NOTOK otherwise
00377  ********************************************************************/
00378 int _TestSubgraph (graphP theSubgraph,
00379                    graphP theGraph)
00380 {
00381   int I,
00382     J;
00383 
00384 /* We clear all visitation flags */
00385   for (I = 0; I < theGraph->N; I++)
00386     theGraph->G[I].visited = 0;
00387 
00388 /* For each vertex... */
00389   for (I = 0; I < theSubgraph->N; I++)
00390 
00391   {
00392 
00393     /* For each neighbor w in the adjacency list of vertex I in the
00394      * subgraph, set the visited flag in w in the graph */
00395     J = theSubgraph->G[I].link[0];
00396     while (J >= 2 * theSubgraph->N)
00397 
00398     {
00399       theGraph->G[theSubgraph->G[J].v].visited = 1;
00400       J = theSubgraph->G[J].link[0];
00401     }
00402 
00403     /* For each neighbor w in the adjacency list of vertex I in the graph,
00404      * clear the visited flag in w in the graph */
00405     J = theGraph->G[I].link[0];
00406     while (J >= 2 * theGraph->N)
00407 
00408     {
00409       theGraph->G[theGraph->G[J].v].visited = 0;
00410       J = theGraph->G[J].link[0];
00411     }
00412 
00413     /* For each neighbor w in the adjacency list of vertex I in the
00414      * subgraph, set the visited flag in w in the graph */
00415     J = theSubgraph->G[I].link[0];
00416     while (J >= 2 * theSubgraph->N)
00417 
00418     {
00419       if (theGraph->G[theSubgraph->G[J].v].visited)
00420         return NOTOK;
00421       J = theSubgraph->G[J].link[0];
00422     }
00423   }
00424   return OK;
00425 }

Generated on Thu Oct 20 14:58:41 2005 for DominoParitySeparator by  doxygen 1.4.5