Path: blob/master/sage/graphs/planarity/graphColorVertices.c
4076 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 "graphColorVertices.h"45#include "graphColorVertices.private.h"4647extern int COLORVERTICES_ID;4849#include "graph.h"5051#if 052#include <malloc.h>53#else54#if !defined(_XOPEN_SOURCE) && !defined(_ISOC99_SOURCE)55#define _XOPEN_SOURCE 60056#endif57#include <stdlib.h> /* ISO C99 also defines malloc() to be there. */58#endif59#include <string.h>60#include <stdio.h>6162extern void _FillVisitedFlags(graphP theGraph, int FillValue);63extern int _TestSubgraph(graphP theSubgraph, graphP theGraph);6465extern void _ColorVertices_Reinitialize(ColorVerticesContext *context);6667/* Private functions exported to system */6869void _AddVertexToDegList(ColorVerticesContext *context, graphP theGraph, int v, int deg);70void _RemoveVertexFromDegList(ColorVerticesContext *context, graphP theGraph, int v, int deg);71int _AssignColorToVertex(ColorVerticesContext *context, graphP theGraph, int v);7273/* Private functions */7475int _GetVertexToReduce(ColorVerticesContext *context, graphP theGraph);76int _IsConstantTimeContractible(ColorVerticesContext *context, int v);77int _GetContractibleNeighbors(ColorVerticesContext *context, int v, int *pu, int *pw);7879/********************************************************************80gp_ColorVertices()8182This is the entry point for requesting a vertex coloring by the83the minimum degree selection method.8485The call pattern is to simply invoke this function on a graph to86color it or recolor it after some mutations. It will invoke87gp_AttachColorVertices() to attach the auxiliary data needed to88performing the coloring, and the attachment short-circuits if89already done.9091After calling this function, call gp_ColorVertices_GetColors() to92obtain the colors or gp_Write() to save the colors. To read a saved93coloring, use gp_AttachColorVertices() then gp_Read().9495Returns OK on success, NOTOK on failure96********************************************************************/97#include "platformTime.h"9899int gp_ColorVertices(graphP theGraph)100{101ColorVerticesContext *context = NULL;102int v, deg;103int u=0, w=0, contractible;104105// Attach the algorithm if it is not already attached106if (gp_AttachColorVertices(theGraph) != OK)107return NOTOK;108109// Ensure there is enough stack to perform this operation.110// At a maximum, the graph reduction will push 7N+M integers.111// One integer is pushed per edge that is hidden. Plus, whether112// a vertex is hidden or identified with another vertex, 7 integers113// are used to store enough information to restore it.114if (sp_NonEmpty(theGraph->theStack))115return NOTOK;116117if (sp_GetCapacity(theGraph->theStack) < 7*theGraph->N + theGraph->M)118{119stackP newStack = sp_New(7*theGraph->N + theGraph->M);120if (newStack == NULL)121return NOTOK;122sp_Free(&theGraph->theStack);123theGraph->theStack = newStack;124}125126// Get the extension context and reinitialize it if necessary127gp_FindExtension(theGraph, COLORVERTICES_ID, (void *)&context);128129if (context->color[0] > -1)130_ColorVertices_Reinitialize(context);131132// Initialize the degree lists, and provide a color for any trivial vertices133for (v = 0; v < theGraph->N; v++)134{135deg = gp_GetVertexDegree(theGraph, v);136_AddVertexToDegList(context, theGraph, v, deg);137138if (deg == 0)139context->color[v] = 0;140}141142// Initialize the visited flags so they can be used during reductions143_FillVisitedFlags(theGraph, 0);144145// Reduce the graph using minimum degree selection146while (context->numVerticesToReduce > 0)147{148v = _GetVertexToReduce(context, theGraph);149150// Find out if v is contractible and the neighbors to contract151contractible = _GetContractibleNeighbors(context, v, &u, &w);152153// Remove the vertex from the graph. This calls the fpHideEdge154// overload, which performs the correct _RemoveVertexFromDegList()155// and _AddVertexToDegList() operations on v and its neighbors.156if (gp_HideVertex(theGraph, v) != OK)157return NOTOK;158159// If v was contractibile, then identify u and w160if (contractible)161{162if (gp_IdentifyVertices(theGraph, u, w, NIL) != OK)163return NOTOK;164}165}166167// Restore the graph one vertex at a time, coloring each vertex distinctly168// from its neighbors as it is restored.169context->colorDetector = (int *) calloc(theGraph->N, sizeof(int));170if (context->colorDetector == NULL)171return NOTOK;172173if (gp_RestoreVertices(theGraph) != OK)174return NOTOK;175176free(context->colorDetector);177context->colorDetector = NULL;178179return OK;180}181182/********************************************************************183_AddVertexToDegList()184185This function adds vertex v to degree list deg.186The current method simply appends the vertex to the degree list.187188This method will be improved later to handle the degree 5 list189specially by prepending those degree 5 vertices that have two190non-adjacent neighbors with a constant degree bound. These vertices191can be specially handled by identifying the non-adjacent neighbors192during reduction so that the neighborhood of v receives only three193colors. This ensures that all planar graphs use at most 5 colors.194Matula, Shiloach and Tarjan (1980) introduced this contraction195method, and the tighter degree bound on the neighbors used in this196implementation is due to Frederickson (1984).197********************************************************************/198199void _AddVertexToDegList(ColorVerticesContext *context, graphP theGraph, int v, int deg)200{201if (deg > 0)202{203if (_IsConstantTimeContractible(context, v))204context->degListHeads[deg] = LCPrepend(context->degLists, context->degListHeads[deg], v);205else206context->degListHeads[deg] = LCAppend(context->degLists, context->degListHeads[deg], v);207208context->numVerticesToReduce++;209}210context->degree[v] = deg;211}212213/********************************************************************214_GetVertexDegree()215********************************************************************/216217int _GetVertexDegree(ColorVerticesContext *context, int v)218{219return context->degree[v];220221// We cache vertex degree values because the API function is O(deg(v)),222// which would make this algorithm implementation have quadratic behavior223// in the worst case224//225// return gp_GetVertexDegree(context->theGraph, v);226}227228/********************************************************************229_IsConstantTimeContractible()230Wrapper function that just returns the result of _GetContractibleNeighbors()231Return TRUE if v is degree 5 and has a pair of non-adjacent neighbors232of degree 7 or lower; FALSE otherwise.233********************************************************************/234235int _IsConstantTimeContractible(ColorVerticesContext *context, int v)236{237int u, w;238return _GetContractibleNeighbors(context, v, &u, &w);239}240241/********************************************************************242_GetContractibleNeighbors()243Wrapper function that just returns the result of _GetContractibleNeighbors()244245This function returns TRUE if the vertex v is degree 5 and has two246non-adjacent neighbors of degree at most 7. In 1980, Matula, Shiloach247and Tarjan proved the sequential contraction method of five-coloring248planar graphs could run in linear time based on deleting any vertices249less than degree 5 and, if none exist, contracting a degree 5 vertex250with two non-adjacent neighbors of degree at most 11. In 1984,251Greg N. Frederickson improved the result to 7.252253When a vertex is being added to the degree list, it is appended254unless this function returns TRUE, in which case it is placed255at the front of the degree 5 list.256When a vertex is removed from a degree list for reduction, it is257tested again, and if this function returns TRUE, then two non-adjacent258neighbors of degree at most 7 are found. The vertex is hidden in259either case, but if the neighbors were found, then they are260identified. In the recursion, the neighbors will get the same261color so that when the vertex is restored, its neighborhood has at262most four colors. The vertex takes the fifth color.263Hence, planar graphs are colored with at most five colors. Non-planar264graphs are still colored, but perhaps with more than five colors since265the 5 list may become empty or may not start with a constant time266contractible vertex (in which case we stick with the constant time267per edge deletion only).268269This function operates in constant time, so it only finds a pair of270contractible neighbors for degree 5 vertices, it determines the degree271of all neighbors in constant time, it determines whether each pair of272low degree neighbors is non-adjacent in constant time, and the degree273bound on the pair of neighbors returned ensures that they can be274identified (including removal of duplicate edges) in constant time.275276Return TRUE if v is degree 5 and has a pair of non-adjacent neighbors277of degree 7 or lower; FALSE otherwise.278279Also returns the two neighbors found if TRUE is returned. The pointer280variables are not altered in the FALSE case.281********************************************************************/282283int _GetContractibleNeighbors(ColorVerticesContext *context, int v, int *pu, int *pw)284{285int lowDegreeNeighbors[5], i, j, n=0, J;286graphP theGraph = context->theGraph;287288// This method is only applicable to degree 5 vertices289if (_GetVertexDegree(context, v) != 5)290return FALSE;291292// Get all neighbors of degree at most 7293J = gp_GetFirstArc(theGraph, v);294while (gp_IsArc(theGraph, J))295{296if (_GetVertexDegree(context, theGraph->G[J].v) <= 7)297lowDegreeNeighbors[n++] = theGraph->G[J].v;298J = gp_GetNextArc(theGraph, J);299}300301// Seek the pair of *non-adjacent* low degree neighbors302for (i=0; i < (n-1); i++)303for (j=i+1; j < n; j++)304if (!gp_IsNeighbor(theGraph, lowDegreeNeighbors[i], lowDegreeNeighbors[j]))305{306*pu = lowDegreeNeighbors[i];307*pw = lowDegreeNeighbors[j];308return TRUE;309}310311// The desired pair of neighbors was not found312return FALSE;313}314315316/********************************************************************317_RemoveVertexFromDegList()318********************************************************************/319320void _RemoveVertexFromDegList(ColorVerticesContext *context, graphP theGraph, int v, int deg)321{322if (deg > 0)323{324context->degListHeads[deg] = LCDelete(context->degLists, context->degListHeads[deg], v);325context->numVerticesToReduce--;326}327}328329/********************************************************************330_GetVertexToReduce()331********************************************************************/332333int _GetVertexToReduce(ColorVerticesContext *context, graphP theGraph)334{335int v = NIL, deg;336337for (deg = 1; deg < theGraph->N; deg++)338{339if (context->degListHeads[deg] != NIL)340{341// Get the first vertex in the list342v = context->degListHeads[deg];343break;344}345}346347return v;348}349350/********************************************************************351_AssignColorToVertex()352********************************************************************/353354int _AssignColorToVertex(ColorVerticesContext *context, graphP theGraph, int v)355{356int J, w, color;357358// Run the neighbor list of v and flag all the colors in use359J = gp_GetFirstArc(theGraph, v);360while (gp_IsArc(theGraph, J))361{362w = theGraph->G[J].v;363context->colorDetector[context->color[w]] = 1;364365J = gp_GetNextArc(theGraph, J);366}367368// Find the least numbered unused color and assign it to v369// Note that this loop never runs more than deg(v) steps370for (color = 0; color < theGraph->N; color++)371{372if (context->colorDetector[color] == 0)373{374context->color[v] = color;375if (context->highestColorUsed < color)376context->highestColorUsed = color;377break;378}379}380381if (context->color[v] < 0)382return NOTOK;383384// Run the neighbor list of v and unflag all the colors in use385J = gp_GetFirstArc(theGraph, v);386while (gp_IsArc(theGraph, J))387{388w = theGraph->G[J].v;389context->colorDetector[context->color[w]] = 0;390391J = gp_GetNextArc(theGraph, J);392}393394return OK;395}396397/********************************************************************398gp_GetNumColorsUsed()399********************************************************************/400401int gp_GetNumColorsUsed(graphP theGraph)402{403ColorVerticesContext *context = (ColorVerticesContext *) gp_GetExtension(theGraph, COLORVERTICES_ID);404return context == NULL ? 0 : context->highestColorUsed+1;405}406407/********************************************************************408gp_ColorVerticesIntegrityCheck()409********************************************************************/410411int gp_ColorVerticesIntegrityCheck(graphP theGraph, graphP origGraph)412{413int I, J, w;414ColorVerticesContext *context = (ColorVerticesContext *) gp_GetExtension(theGraph, COLORVERTICES_ID);415416if (theGraph == NULL || origGraph == NULL || context == NULL)417return NOTOK;418419if (gp_GetNumColorsUsed(theGraph) <= 0 && theGraph->M > 0)420return NOTOK;421422if (_TestSubgraph(theGraph, origGraph) != TRUE)423return NOTOK;424425if (_TestSubgraph(origGraph, theGraph) != TRUE)426return NOTOK;427428for (I=0; I < theGraph->N; I++)429{430J = gp_GetFirstArc(theGraph, I);431while (gp_IsArc(theGraph, J))432{433w = theGraph->G[J].v;434if (context->color[I] < 0 || context->color[I] == context->color[w])435return NOTOK;436437J = gp_GetNextArc(theGraph, J);438}439}440441return OK;442}443444445