int _CheckAllVerticesOnExternalFace(graphP theGraph)
{
    int v;

    // Mark all vertices unvisited
    _ClearVertexVisitedFlags(theGraph, FALSE);

    // For each connected component, walk its external face and
    // mark the vertices as visited
    for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v); v++)
    {
         if (gp_IsDFSTreeRoot(theGraph, v))
        	 _MarkExternalFaceVertices(theGraph, v);
    }

    // If any vertex is unvisited, then the embedding is not an outerplanar
    // embedding, so we return NOTOK
    for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v); v++)
        if (!gp_GetVertexVisited(theGraph, v))
            return NOTOK;

    // All vertices were found on external faces of the connected components
    // so the embedding is an outerplanar embedding and we return OK
    return OK;
}
Beispiel #2
0
int  _DeleteUnmarkedVerticesAndEdges(graphP theGraph)
{
    int  v, e;

    /* All of the forward and back arcs of all of the edge records
       were removed from the adjacency lists in the planarity algorithm
       preprocessing.  We now put them back into the adjacency lists
       (and we do not mark them), so they can be properly deleted below. */

    for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v); v++)
    {
        while (gp_IsArc(e = gp_GetVertexFwdArcList(theGraph, v)))
            _AddBackEdge(theGraph, v, gp_GetNeighbor(theGraph, e));
    }

    /* Now we delete all unmarked edges.  We don't delete vertices from the
       embedding, but the ones we should delete will become degree zero. */

    for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v); v++)
    {
        e = gp_GetFirstArc(theGraph, v);
        while (gp_IsArc(e))
        {
            if (gp_GetEdgeVisited(theGraph, e))
                e = gp_GetNextArc(theGraph, e);
            else e = gp_DeleteEdge(theGraph, e, 0);
        }
    }

    return OK;
}
void SaveAsciiGraph(graphP theGraph, char *filename)
{
    int  e, EsizeOccupied, vertexLabelFix;
    FILE *outfile = fopen(filename, "wt");
    fprintf(outfile, "%s\n", filename);

    // This edge list file format uses 1-based vertex numbering, and the current code
    // internally uses 1-based indexing by default, so this vertex label 'fix' adds zero
    // But earlier code used 0-based indexing and added one on output, so we replicate
    // that behavior in case the current code has been compiled with zero-based indexing.
    vertexLabelFix = 1 - gp_GetFirstVertex(theGraph);

    // Iterate over the edges of the graph
    EsizeOccupied = gp_EdgeInUseIndexBound(theGraph);
    for (e = gp_GetFirstEdge(theGraph); e < EsizeOccupied; e+=2)
    {
        // Only output edges that haven't been deleted (i.e. skip the edge holes)
        if (gp_EdgeInUse(theGraph, e))
        {
            fprintf(outfile, "%d %d\n",
                    gp_GetNeighbor(theGraph, e) + vertexLabelFix,
                    gp_GetNeighbor(theGraph, e+1) + vertexLabelFix);
        }
    }

    // Since vertex numbers are at least 1, this indicates the end of the edge list
    fprintf(outfile, "0 0\n");

    fclose(outfile);
}
int gp_ColorVerticesIntegrityCheck(graphP theGraph, graphP origGraph)
{
    int v, w, e;
    ColorVerticesContext *context = (ColorVerticesContext *) gp_GetExtension(theGraph, COLORVERTICES_ID);

    if (theGraph == NULL || origGraph == NULL || context == NULL)
        return NOTOK;

    if (gp_GetNumColorsUsed(theGraph) <= 0 && theGraph->M > 0)
        return NOTOK;

    if (_TestSubgraph(theGraph, origGraph) != TRUE)
        return NOTOK;

    if (_TestSubgraph(origGraph, theGraph) != TRUE)
        return NOTOK;

    for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v); v++)
    {
        e = gp_GetFirstArc(theGraph, v);
        while (gp_IsArc(e))
        {
            w = gp_GetNeighbor(theGraph, e);
            if (context->color[v] < 0 || context->color[v] == context->color[w])
                return NOTOK;

            e = gp_GetNextArc(theGraph, e);
        }
    }

    return OK;
}
int  _getImageVertices(graphP theGraph, int *degrees, int maxDegree,
                       int *imageVerts, int maxNumImageVerts)
{
int K, v, imageVertPos, degree;

     for (degree = 0; degree <= maxDegree; degree++)
          degrees[degree] = 0;

     for (K = 0; K < maxNumImageVerts; K++)
          imageVerts[K] = NIL;

     imageVertPos = 0;

     for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v); v++)
     {
          degree = gp_GetVertexDegree(theGraph, v);
          if (degree == 1)
              return NOTOK;
          if (degree > maxDegree)
              return NOTOK;

          degrees[degree]++;

          if (imageVertPos < maxNumImageVerts && degree > 2)
              imageVerts[imageVertPos++] = v;
          else if (degree > 2)
              return NOTOK;
     }

     return OK;
}
void _CreateSeparatedDFSChildLists(graphP theGraph, K33SearchContext *context)
{
int *buckets;
listCollectionP bin;
int v, L, DFSParent, theList;

     buckets = context->buckets;
     bin = context->bin;

     // Initialize the bin and all the buckets to be empty
     LCReset(bin);
     for (L = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, L); L++)
          buckets[L] = NIL;

     // For each vertex, add it to the bucket whose index is equal to the lowpoint of the vertex.

     for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v); v++)
     {
          L = gp_GetVertexLowpoint(theGraph, v);
          buckets[L] = LCAppend(bin, buckets[L], v);
     }

     // For each bucket, add each vertex in the bucket to the separatedDFSChildList of its DFSParent.
     // Since lower numbered buckets are processed before higher numbered buckets, vertices with lower
     // lowpoint values are added before those with higher lowpoint values, so the separatedDFSChildList
     // of each vertex is sorted by lowpoint
     for (L = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, L); L++)
     {
    	  v = buckets[L];

    	  // Loop through all the vertices with lowpoint L, putting each in the list of its parent
		  while (gp_IsVertex(v))
		  {
			  DFSParent = gp_GetVertexParent(theGraph, v);

			  if (gp_IsVertex(DFSParent) && DFSParent != v)
			  {
				  theList = context->VI[DFSParent].separatedDFSChildList;
				  theList = LCAppend(context->separatedDFSChildLists, theList, v);
				  context->VI[DFSParent].separatedDFSChildList = theList;
			  }

			  v = LCGetNext(bin, buckets[L], v);
		  }
     }
}
int _TestForK33GraphObstruction(graphP theGraph, int *degrees, int *imageVerts)
{
int  v, K, imageVertPos, temp, success;

	if (degrees[4] != 0)
		return FALSE;

	if (degrees[3] != 6)
    	 return FALSE;

     /* Partition the six image vertices into two sets of 3
            (or report failure) */

     for (imageVertPos = 3; imageVertPos < 6; imageVertPos++)
     {
          K = 0;
          success = FALSE;
          do {
             if (_TestPath(theGraph, imageVerts[imageVertPos], imageVerts[0]) == TRUE)
             {
                 success = TRUE;
                 break;
             }

             K++;
             temp = imageVerts[K];
             imageVerts[K] = imageVerts[imageVertPos];
             imageVerts[imageVertPos] = temp;
          }  while (K < 3);

          if (!success)
              return FALSE;
     }

     /* Now test the paths between each of the first three vertices and
            each of the last three vertices */

     _ClearVertexVisitedFlags(theGraph, FALSE);

     for (imageVertPos=0; imageVertPos<3; imageVertPos++)
          for (K=3; K<6; K++)
               if (_TestPath(theGraph, imageVerts[imageVertPos],
                                       imageVerts[K]) != TRUE)
                   return FALSE;

     for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v); v++)
          if (gp_GetVertexVisited(theGraph, v))
              degrees[2]--;

     /* If every degree 2 vertex is used in a path between image
            vertices, then there are no extra pieces of the graph
            in theGraph.  Specifically, the prior tests identify
            a K_{3,3} and ensure that nothing else could exist in the
            graph except extra degree 2 vertices, which must be
            joined in a cycle so that all are degree 2. */

     return degrees[2] == 0 ? TRUE : FALSE;
}
int _TestForCompleteGraphObstruction(graphP theGraph, int numVerts,
                                     int *degrees, int *imageVerts)
{
    int v, w;

    // We need to make sure we have numVerts vertices of degree numVerts-1
    // For example, if numVerts==5, then we're looking for a K5, so we
    // need to have degrees[4] == 5 (5 vertices of degree 4)
    if (degrees[numVerts-1] != numVerts)
        return FALSE;

    // All vertices need to be degree 0, degree 2 or degree numVerts-1
    if (degrees[0]+degrees[2]+degrees[numVerts-1] != theGraph->N)
        return FALSE;

    // We clear all the vertex visited flags
    _ClearVertexVisitedFlags(theGraph, FALSE);

    // For each pair of image vertices, we test that there is a path
    // between the two vertices.  If so, the visited flags of the
    // internal vertices along the path are marked
    //
    for (v = 0; v < numVerts; v++)
        for (w = 0; w < numVerts; w++)
           if (v != w)
               if (_TestPath(theGraph, imageVerts[v],
                                       imageVerts[w]) != TRUE)
                   return FALSE;

    // The visited flags should have marked only degree two vertices,
    // so for every marked vertex, we subtract one from the count of
    // the degree two vertices.
    for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v); v++)
        if (gp_GetVertexVisited(theGraph, v))
            degrees[2]--;

    /* If every degree 2 vertex is used in a path between image
        vertices, then there are no extra pieces of the graph
        in theGraph.  Specifically, the prior tests identify
        a K_5 and ensure that nothing else could exist in the
        graph except extra degree 2 vertices, which must be
        joined in a cycle so that all are degree 2. */

    return degrees[2] == 0 ? TRUE : FALSE;
}
/********************************************************************
 _K33Search_InitStructures()
 ********************************************************************/
int  _K33Search_InitStructures(K33SearchContext *context)
{
#if NIL == 0 || NIL == -1
	memset(context->VI, NIL_CHAR, gp_PrimaryVertexIndexBound(context->theGraph) * sizeof(K33Search_VertexInfo));
	memset(context->E, NIL_CHAR, gp_EdgeIndexBound(context->theGraph) * sizeof(K33Search_EdgeRec));
#else
	 graphP theGraph = context->theGraph;
     int v, e, Esize;

     if (theGraph->N <= 0)
         return OK;

     for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v); v++)
          _K33Search_InitVertexInfo(context, v);

     Esize = gp_EdgeIndexBound(theGraph);
     for (e = gp_GetFirstEdge(theGraph); e < Esize; e++)
          _K33Search_InitEdgeRec(context, e);
#endif

     return OK;
}
/********************************************************************
 _CreateBackArcLists()
 ********************************************************************/
void _CreateBackArcLists(graphP theGraph, K33SearchContext *context)
{
	int v, e, eTwin, ancestor;

	for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v); v++)
    {
    	e = gp_GetVertexFwdArcList(theGraph, v);
        while (gp_IsArc(e))
        {
        	// Get the ancestor endpoint and the associated back arc
        	ancestor = gp_GetNeighbor(theGraph, e);
        	eTwin = gp_GetTwinArc(theGraph, e);

        	// Put it into the back arc list of the ancestor
            if (gp_IsNotArc(context->VI[ancestor].backArcList))
            {
                context->VI[ancestor].backArcList = eTwin;
                gp_SetPrevArc(theGraph, eTwin, eTwin);
                gp_SetNextArc(theGraph, eTwin, eTwin);
            }
            else
            {
            	int eHead = context->VI[ancestor].backArcList;
            	int eTail = gp_GetPrevArc(theGraph, eHead);
        		gp_SetPrevArc(theGraph, eTwin, eTail);
        		gp_SetNextArc(theGraph, eTwin, eHead);
        		gp_SetPrevArc(theGraph, eHead, eTwin);
        		gp_SetNextArc(theGraph, eTail, eTwin);
            }

        	// Advance to the next forward edge
			e = gp_GetNextArc(theGraph, e);
			if (e == gp_GetVertexFwdArcList(theGraph, v))
				e = NIL;
        }
    }
}
int gp_ColorVertices(graphP theGraph)
{
    ColorVerticesContext *context = NULL;
    int v, deg;
    int u=0, w=0, contractible;

    // Attach the algorithm if it is not already attached
    if (gp_AttachColorVertices(theGraph) != OK)
        return NOTOK;

    // Ensure there is enough stack to perform this operation.
    // At a maximum, the graph reduction will push 7N+M integers.
    // One integer is pushed per edge that is hidden. Plus, whether
    // a vertex is hidden or identified with another vertex, 7 integers
    // are used to store enough information to restore it.
    if (sp_NonEmpty(theGraph->theStack))
        return NOTOK;

    if (sp_GetCapacity(theGraph->theStack) < 7*theGraph->N + theGraph->M)
    {
        stackP newStack = sp_New(7*theGraph->N + theGraph->M);
        if (newStack == NULL)
            return NOTOK;
        sp_Free(&theGraph->theStack);
        theGraph->theStack = newStack;
    }

    // Get the extension context and reinitialize it if necessary
    gp_FindExtension(theGraph, COLORVERTICES_ID, (void *)&context);

    if (context->color[0] > -1)
        _ColorVertices_Reinitialize(context);

    // Initialize the degree lists, and provide a color for any trivial vertices
    for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v); v++)
    {
        deg = gp_GetVertexDegree(theGraph, v);
        _AddVertexToDegList(context, theGraph, v, deg);

        if (deg == 0)
            context->color[v] = 0;
    }

    // Initialize the vertex visited flags so they can be used during reductions
    _ClearVertexVisitedFlags(theGraph, FALSE);

    // Reduce the graph using minimum degree selection
    while (context->numVerticesToReduce > 0)
    {
        v = _GetVertexToReduce(context, theGraph);

        // Find out if v is contractible and the neighbors to contract
        contractible = _GetContractibleNeighbors(context, v, &u, &w);

        // Remove the vertex from the graph. This calls the fpHideEdge
        // overload, which performs the correct _RemoveVertexFromDegList()
        // and _AddVertexToDegList() operations on v and its neighbors.
        if (gp_HideVertex(theGraph, v) != OK)
            return NOTOK;

        // If v was contractibile, then identify u and w
        if (contractible)
        {
            if (gp_IdentifyVertices(theGraph, u, w, NIL) != OK)
                return NOTOK;
        }
    }

    // Restore the graph one vertex at a time, coloring each vertex distinctly
    // from its neighbors as it is restored.
    context->colorDetector = (int *) calloc(theGraph->N, sizeof(int));
    if (context->colorDetector == NULL)
        return NOTOK;

    if (gp_RestoreVertices(theGraph) != OK)
        return NOTOK;

    free(context->colorDetector);
    context->colorDetector = NULL;

    return OK;
}
int  _TestSubgraph(graphP theSubgraph, graphP theGraph)
{
int v, e, degreeCount;
int Result = TRUE;
int invokeSortOnGraph = FALSE;
int invokeSortOnSubgraph = FALSE;

    // If the graph is not sorted by DFI, but the alleged subgraph is,
    // then "unsort" the alleged subgraph so both have the same vertex order
    if (!(theGraph->internalFlags & FLAGS_SORTEDBYDFI) &&
         (theSubgraph->internalFlags & FLAGS_SORTEDBYDFI))
    {
        invokeSortOnSubgraph = TRUE;
        gp_SortVertices(theSubgraph);
    }

    // If the graph is not sorted by DFI, but the alleged subgraph is,
    // then "unsort" the alleged subgraph so both have the same vertex order
    if (!(theSubgraph->internalFlags & FLAGS_SORTEDBYDFI) &&
         (theGraph->internalFlags & FLAGS_SORTEDBYDFI))
    {
        invokeSortOnGraph = TRUE;
        gp_SortVertices(theGraph);
    }

/* We clear all visitation flags */

     _ClearVertexVisitedFlags(theGraph, FALSE);

/* For each vertex... */
     for (v = gp_GetFirstVertex(theSubgraph), degreeCount = 0; gp_VertexInRange(theSubgraph, v); v++)
     {
          /* For each neighbor w in the adjacency list of vertex v in the
                subgraph, set the visited flag in w in the graph */

          e = gp_GetFirstArc(theSubgraph, v);
          while (gp_IsArc(e))
          {
        	  if (gp_IsNotVertex(gp_GetNeighbor(theSubgraph, e)))
        	  {
        		  Result = FALSE;
        		  break;
        	  }
        	  degreeCount++;
        	  gp_SetVertexVisited(theGraph, gp_GetNeighbor(theSubgraph, e));
              e = gp_GetNextArc(theSubgraph, e);
          }

          if (Result != TRUE)
        	  break;

          /* For each neighbor w in the adjacency list of vertex v in the graph,
                clear the visited flag in w in the graph */

          e = gp_GetFirstArc(theGraph, v);
          while (gp_IsArc(e))
          {
        	  if (gp_IsNotVertex(gp_GetNeighbor(theGraph, e)))
        	  {
        		  Result = FALSE;
        		  break;
        	  }
        	  gp_ClearVertexVisited(theGraph, gp_GetNeighbor(theGraph, e));
              e = gp_GetNextArc(theGraph, e);
          }

          if (Result != TRUE)
        	  break;

          /* For each neighbor w in the adjacency list of vertex v in the subgraph,
             ensure that the visited flag in w was cleared (otherwise, the "subgraph"
             would incorrectly contain an adjacency not contained in the ("super") graph) */

          e = gp_GetFirstArc(theSubgraph, v);
          while (gp_IsArc(e))
          {
              if (gp_GetVertexVisited(theGraph, gp_GetNeighbor(theSubgraph, e)))
              {
            	  Result = FALSE;
            	  break;
              }
              e = gp_GetNextArc(theSubgraph, e);
          }

          if (Result != TRUE)
        	  break;
     }

    // Restore the DFI sort order of either graph if it had to be reordered at the start
    if (invokeSortOnSubgraph)
        gp_SortVertices(theSubgraph);
    if (invokeSortOnGraph)
        gp_SortVertices(theGraph);

    // Assuming theSubgraph is a subgraph, we also do an extra integrity check to ensure
    // proper edge array utilization
    if (Result == TRUE)
    {
    	// If the edge count is wrong, we fail the subgraph test in a way that invokes
    	// the name NOTOK so that in debug mode there is more trace on the failure.
    	if (degreeCount != 2*theSubgraph->M)
    		Result = NOTOK == FALSE ? NOTOK : FALSE;
    }

     return Result;
}
int _TestForK23GraphObstruction(graphP theGraph, int *degrees, int *imageVerts)
{
int  v, e, imageVertPos;

     // This function operates over the imageVerts results produced by
     // getImageVertices, which only finds vertices of degree 3 or higher.
     // So, for a K2,3, there must be exactly two degree 3 vertices and
     // no degree 4 vertices.
     if (degrees[3] != 2)
         return FALSE;

     // For K_{2,3}, the three vertices of degree 2 were not
     // detected as image vertices because degree 2 vertices
     // are indistinguishable from the internal path vertices
     // between the image vertices.  So, here we acknowledge
     // that more image vertices need to be selected.
     imageVertPos = 2;

     // Assign the remaining three image vertices to be the
     // neighbors of the first degree 3 image vertex.
     // Ensure that each is distinct from the second
     // degree 3 image vertex. This must be the case because
     // the two degree 3 image vertices are in the same partition
     // and hence must not be adjacent.

     e = gp_GetFirstArc(theGraph, imageVerts[0]);
     while (gp_IsArc(e))
     {
         imageVerts[imageVertPos] = gp_GetNeighbor(theGraph, e);
         if (imageVerts[imageVertPos] == imageVerts[1])
             return FALSE;
         imageVertPos++;
         e = gp_GetNextArc(theGraph, e);
     }

     /* The paths from imageVerts[0] to each of the new degree 2
          image vertices are the edges we just traversed.
          Now test the paths between each of the degree 2 image
          vertices and imageVerts[1]. */

     _ClearVertexVisitedFlags(theGraph, FALSE);

     for (imageVertPos=2; imageVertPos<5; imageVertPos++)
     {
          if (_TestPath(theGraph, imageVerts[imageVertPos],
                                  imageVerts[1]) != TRUE)
              return FALSE;

          gp_SetVertexVisited(theGraph, imageVerts[imageVertPos]);
     }

     for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v); v++)
          if (gp_GetVertexVisited(theGraph, v))
              degrees[2]--;

     /* If every degree 2 vertex is used in a path between the
          two degree 3 image vertices, then there are no extra
          pieces of the graph in theGraph.  Specifically, the
          prior tests identify a K_{2,3} and ensure that nothing
          else could exist in the graph... except extra degree 2
          vertices joined in a cycle. We return NOTOK in that case. */

     return degrees[2] == 0 ? TRUE : FALSE;
}
int  _CheckEmbeddingFacialIntegrity(graphP theGraph)
{
stackP theStack = theGraph->theStack;
int EsizeOccupied, v, e, eTwin, eStart, eNext, NumFaces, connectedComponents;

     if (theGraph == NULL)
         return NOTOK;

/* The stack need only contain 2M entries, one for each edge record. With
        max M at 3N, this amounts to 6N integers of space.  The embedding
        structure already contains this stack, so we just make sure it
        starts out empty. */

     sp_ClearStack(theStack);

/* Push all arcs and set them to unvisited */

	 EsizeOccupied = gp_EdgeInUseIndexBound(theGraph);
     for (e = gp_GetFirstEdge(theGraph); e < EsizeOccupied; e+=2)
     {
    	  // Except skip edge holes
          if (gp_EdgeInUse(theGraph, e))
          {
			  sp_Push(theStack, e);
			  gp_ClearEdgeVisited(theGraph, e);
			  eTwin = gp_GetTwinArc(theGraph, e);
			  sp_Push(theStack, eTwin);
			  gp_ClearEdgeVisited(theGraph, eTwin);
          }
     }

     // There are M edges, so we better have pushed 2M arcs just now
     // i.e. testing that the continue above skipped only edge holes
     if (sp_GetCurrentSize(theStack) != 2*theGraph->M)
    	 return NOTOK;


/* Read faces until every arc is used */

     NumFaces = 0;
     while (sp_NonEmpty(theStack))
     {
            /* Get an arc; if it has already been used by a face, then
                don't use it to traverse a new face */
            sp_Pop(theStack, eStart);
            if (gp_GetEdgeVisited(theGraph, eStart)) continue;

            e = eStart;
            do {
                eNext = gp_GetNextArcCircular(theGraph, gp_GetTwinArc(theGraph, e));
                if (gp_GetEdgeVisited(theGraph, eNext))
                    return NOTOK;
                gp_SetEdgeVisited(theGraph, eNext);
                e = eNext;
            } while (e != eStart);
            NumFaces++;
     }

/* Count the external face once rather than once per connected component;
    each connected component is detected by the fact that it has no
    DFS parent, except in the case of isolated vertices, no face was counted
    so we do not subtract one. */

     connectedComponents = 0;
     for (v = gp_GetFirstVertex(theGraph); gp_VertexInRange(theGraph, v); v++)
     {
          if (gp_IsDFSTreeRoot(theGraph, v))
          {
              if (gp_GetVertexDegree(theGraph, v) > 0)
                  NumFaces--;
              connectedComponents++;
          }
     }

     NumFaces++;

/* Test number of faces using the extended Euler's formula.
     For connected components, Euler's formula is f=m-n+2, but
     for disconnected graphs it is extended to f=m-n+1+c where
     c is the number of connected components.*/

     return NumFaces == theGraph->M - theGraph->N + 1 + connectedComponents
            ? OK : NOTOK;
}