Path: blob/master/sage/graphs/planarity/planarityRandomGraphs.c
4057 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 "planarity.h"4546void GetNumberIfZero(int *pNum, char *prompt, int min, int max);47void ReinitializeGraph(graphP *pGraph, int ReuseGraphs, char command);48graphP MakeGraph(int Size, char command);4950/****************************************************************************51RandomGraphs()52Top-level method to randomly generate graphs to test the algorithm given by53the command parameter.54The number of graphs to generate, and the number of vertices for each graph,55can be sent as the second and third params. For each that is sent as zero,56this method will prompt the user for a value.57****************************************************************************/5859#define NUM_MINORS 96061int RandomGraphs(char command, int NumGraphs, int SizeOfGraphs)62{63char theFileName[256];64int I, countUpdateFreq;65int Result=OK, MainStatistic=0;66int ObstructionMinorFreqs[NUM_MINORS];67graphP theGraph=NULL, origGraph=NULL;68platform_time start, end;69int embedFlags = GetEmbedFlags(command);70int ReuseGraphs = TRUE;7172GetNumberIfZero(&NumGraphs, "Enter number of graphs to generate:", 1, 1000000000);73GetNumberIfZero(&SizeOfGraphs, "Enter size of graphs:", 1, 10000);7475theGraph = MakeGraph(SizeOfGraphs, command);76origGraph = MakeGraph(SizeOfGraphs, command);77if (theGraph == NULL || origGraph == NULL)78{79gp_Free(&theGraph);80return NOTOK;81}8283// Initialize a secondary statistics array84for (I=0; I<NUM_MINORS; I++)85ObstructionMinorFreqs[I] = 0;8687// Seed the random number generator with "now". Do it after any prompting88// to tie randomness to human process of answering the prompt.89srand(time(NULL));9091// Select a counter update frequency that updates more frequently with larger graphs92// and which is relatively prime with 10 so that all digits of the count will change93// even though we aren't showing the count value on every iteration94countUpdateFreq = 3579 / SizeOfGraphs;95countUpdateFreq = countUpdateFreq < 1 ? 1 : countUpdateFreq;96countUpdateFreq = countUpdateFreq % 2 == 0 ? countUpdateFreq+1 : countUpdateFreq;97countUpdateFreq = countUpdateFreq % 5 == 0 ? countUpdateFreq+2 : countUpdateFreq;9899// Start the count100fprintf(stdout, "0\r");101fflush(stdout);102103// Start the timer104platform_GetTime(start);105106// Generate and process the number of graphs requested107for (I=0; I < NumGraphs; I++)108{109if ((Result = gp_CreateRandomGraph(theGraph)) == OK)110{111if (tolower(OrigOut)=='y')112{113sprintf(theFileName, "random\\%d.txt", I%10);114gp_Write(theGraph, theFileName, WRITE_ADJLIST);115}116117gp_CopyGraph(origGraph, theGraph);118119if (strchr("pdo234", command))120{121Result = gp_Embed(theGraph, embedFlags);122123if (gp_TestEmbedResultIntegrity(theGraph, origGraph, Result) != Result)124Result = NOTOK;125126if (Result == OK)127{128MainStatistic++;129130if (tolower(EmbeddableOut) == 'y')131{132sprintf(theFileName, "embedded\\%d.txt", I%10);133gp_Write(theGraph, theFileName, WRITE_ADJMATRIX);134}135136if (tolower(AdjListsForEmbeddingsOut) == 'y')137{138sprintf(theFileName, "adjlist\\%d.txt", I%10);139gp_Write(theGraph, theFileName, WRITE_ADJLIST);140}141}142else if (Result == NONEMBEDDABLE)143{144if (embedFlags == EMBEDFLAGS_PLANAR || embedFlags == EMBEDFLAGS_OUTERPLANAR)145{146if (theGraph->IC.minorType & MINORTYPE_A)147ObstructionMinorFreqs[0] ++;148else if (theGraph->IC.minorType & MINORTYPE_B)149ObstructionMinorFreqs[1] ++;150else if (theGraph->IC.minorType & MINORTYPE_C)151ObstructionMinorFreqs[2] ++;152else if (theGraph->IC.minorType & MINORTYPE_D)153ObstructionMinorFreqs[3] ++;154else if (theGraph->IC.minorType & MINORTYPE_E)155ObstructionMinorFreqs[4] ++;156157if (theGraph->IC.minorType & MINORTYPE_E1)158ObstructionMinorFreqs[5] ++;159else if (theGraph->IC.minorType & MINORTYPE_E2)160ObstructionMinorFreqs[6] ++;161else if (theGraph->IC.minorType & MINORTYPE_E3)162ObstructionMinorFreqs[7] ++;163else if (theGraph->IC.minorType & MINORTYPE_E4)164ObstructionMinorFreqs[8] ++;165166if (tolower(ObstructedOut) == 'y')167{168sprintf(theFileName, "obstructed\\%d.txt", I%10);169gp_Write(theGraph, theFileName, WRITE_ADJMATRIX);170}171}172}173}174else if (command == 'c')175{176if ((Result = gp_ColorVertices(theGraph)) == OK)177Result = gp_ColorVerticesIntegrityCheck(theGraph, origGraph);178if (Result == OK && gp_GetNumColorsUsed(theGraph) <= 5)179MainStatistic++;180}181182// If there is an error in processing, then write the file for debugging183if (Result != OK && Result != NONEMBEDDABLE)184{185sprintf(theFileName, "error\\%d.txt", I%10);186gp_Write(origGraph, theFileName, WRITE_ADJLIST);187}188}189190// Reinitialize or recreate graphs for next iteration191ReinitializeGraph(&theGraph, ReuseGraphs, command);192ReinitializeGraph(&origGraph, ReuseGraphs, command);193194// Show progress, but not so often that it bogs down progress195if (quietMode == 'n' && (I+1) % countUpdateFreq == 0)196{197fprintf(stdout, "%d\r", I+1);198fflush(stdout);199}200201// Terminate loop on error202if (Result != OK && Result != NONEMBEDDABLE)203{204ErrorMessage("\nError found\n");205Result = NOTOK;206break;207}208}209210// Stop the timer211platform_GetTime(end);212213// Finish the count214fprintf(stdout, "%d\n", NumGraphs);215fflush(stdout);216217// Free the graph structures created before the loop218gp_Free(&theGraph);219gp_Free(&origGraph);220221// Print some demographic results222if (Result == OK || Result == NONEMBEDDABLE)223Message("\nNo Errors Found.");224sprintf(Line, "\nDone (%.3lf seconds).\n", platform_GetDuration(start,end));225Message(Line);226227// Report statistics for planar or outerplanar embedding228if (embedFlags == EMBEDFLAGS_PLANAR || embedFlags == EMBEDFLAGS_OUTERPLANAR)229{230sprintf(Line, "Num Embedded=%d.\n", MainStatistic);231Message(Line);232233for (I=0; I<5; I++)234{235// Outerplanarity does not produces minors C and D236if (embedFlags == EMBEDFLAGS_OUTERPLANAR && (I==2 || I==3))237continue;238239sprintf(Line, "Minor %c = %d\n", I+'A', ObstructionMinorFreqs[I]);240Message(Line);241}242243if (!(embedFlags & ~EMBEDFLAGS_PLANAR))244{245sprintf(Line, "\nNote: E1 are added to C, E2 are added to A, and E=E3+E4+K5 homeomorphs.\n");246Message(Line);247248for (I=5; I<NUM_MINORS; I++)249{250sprintf(Line, "Minor E%d = %d\n", I-4, ObstructionMinorFreqs[I]);251Message(Line);252}253}254}255256// Report statistics for graph drawing257else if (embedFlags == EMBEDFLAGS_DRAWPLANAR)258{259sprintf(Line, "Num Graphs Embedded and Drawn=%d.\n", MainStatistic);260Message(Line);261}262263// Report statistics for subgraph homeomorphism algorithms264else if (embedFlags == EMBEDFLAGS_SEARCHFORK23)265{266sprintf(Line, "Of the generated graphs, %d did not contain a K_{2,3} homeomorph as a subgraph.\n", MainStatistic);267Message(Line);268}269else if (embedFlags == EMBEDFLAGS_SEARCHFORK33)270{271sprintf(Line, "Of the generated graphs, %d did not contain a K_{3,3} homeomorph as a subgraph.\n", MainStatistic);272Message(Line);273}274else if (embedFlags == EMBEDFLAGS_SEARCHFORK4)275{276sprintf(Line, "Of the generated graphs, %d did not contain a K_4 homeomorph as a subgraph.\n", MainStatistic);277Message(Line);278}279280// Report statistics for vertex coloring281else if (command == 'c')282{283sprintf(Line, "Num Graphs colored with 5 or fewer colors=%d.\n", MainStatistic);284Message(Line);285}286287FlushConsole(stdout);288289return Result==OK || Result==NONEMBEDDABLE ? OK : NOTOK;290}291292/****************************************************************************293GetNumberIfZero()294Internal function that gets a number if the given *pNum is zero.295The prompt is displayed if the number must be obtained from the user.296Whether the given number is used or obtained from the user, the function297ensures it is in the range [min, max] and assigns the midpoint value if298it is not.299****************************************************************************/300301void GetNumberIfZero(int *pNum, char *prompt, int min, int max)302{303if (*pNum == 0)304{305Prompt(prompt);306scanf(" %d", pNum);307}308309if (min < 1) min = 1;310if (max < min) max = min;311312if (*pNum < min || *pNum > max)313{314*pNum = (max + min) / 2;315sprintf(Line, "Number out of range [%d, %d]; changed to %d\n", min, max, *pNum);316ErrorMessage(Line);317}318}319320/****************************************************************************321MakeGraph()322Internal function that makes a new graph, initializes it, and attaches an323algorithm to it based on the command.324****************************************************************************/325326graphP MakeGraph(int Size, char command)327{328graphP theGraph;329if ((theGraph = gp_New()) == NULL || gp_InitGraph(theGraph, Size) != OK)330{331ErrorMessage("Error creating space for a graph of the given size.\n");332gp_Free(&theGraph);333return NULL;334}335336// Enable the appropriate feature. Although the same code appears in SpecificGraph,337// it is deliberately not separated to a common utility because SpecificGraph is338// used as a self-contained tutorial. It is not that hard to update both locations339// when new algorithms are added.340341switch (command)342{343case 'd' : gp_AttachDrawPlanar(theGraph); break;344case '2' : gp_AttachK23Search(theGraph); break;345case '3' : gp_AttachK33Search(theGraph); break;346case '4' : gp_AttachK4Search(theGraph); break;347case 'c' : gp_AttachColorVertices(theGraph); break;348}349350return theGraph;351}352353/****************************************************************************354ReinitializeGraph()355Internal function that will either reinitialize the given graph or free it356and make a new one just like it.357****************************************************************************/358359void ReinitializeGraph(graphP *pGraph, int ReuseGraphs, char command)360{361if (ReuseGraphs)362gp_ReinitializeGraph(*pGraph);363else364{365graphP newGraph = MakeGraph((*pGraph)->N, command);366gp_Free(pGraph);367*pGraph = newGraph;368}369}370371/****************************************************************************372Creates a random maximal planar graph, then adds 'extraEdges' edges to it.373****************************************************************************/374375int RandomGraph(char command, int extraEdges, int numVertices, char *outfileName, char *outfile2Name)376{377int Result;378platform_time start, end;379graphP theGraph=NULL, origGraph;380int embedFlags = GetEmbedFlags(command);381char saveEdgeListFormat;382383GetNumberIfZero(&numVertices, "Enter number of vertices:", 1, 1000000);384if ((theGraph = MakeGraph(numVertices, command)) == NULL)385return NOTOK;386387srand(time(NULL));388389Message("Creating the random graph...\n");390platform_GetTime(start);391if (gp_CreateRandomGraphEx(theGraph, 3*numVertices-6+extraEdges) != OK)392{393ErrorMessage("gp_CreateRandomGraphEx() failed\n");394return NOTOK;395}396platform_GetTime(end);397398sprintf(Line, "Created random graph with %d edges in %.3lf seconds. ", theGraph->M, platform_GetDuration(start,end));399Message(Line);400FlushConsole(stdout);401402// The user may have requested a copy of the random graph before processing403if (outfile2Name != NULL)404{405gp_Write(theGraph, outfile2Name, WRITE_ADJLIST);406}407408origGraph = gp_DupGraph(theGraph);409410// Do the requested algorithm on the randomly generated graph411Message("Now processing\n");412FlushConsole(stdout);413414if (strchr("pdo234", command))415{416platform_GetTime(start);417Result = gp_Embed(theGraph, embedFlags);418platform_GetTime(end);419420gp_SortVertices(theGraph);421422if (gp_TestEmbedResultIntegrity(theGraph, origGraph, Result) != Result)423Result = NOTOK;424}425else if (command == 'c')426{427platform_GetTime(start);428Result = gp_ColorVertices(theGraph);429platform_GetTime(end);430}431else432Result = NOTOK;433434// Write what the algorithm determined and how long it took435WriteAlgorithmResults(theGraph, Result, command, start, end, NULL);436437// On successful algorithm result, write the output file and see if the438// user wants the edge list formatted file.439if (Result == OK || Result == NONEMBEDDABLE)440{441if (outfileName != NULL)442gp_Write(theGraph, outfileName, WRITE_ADJLIST);443444Prompt("Do you want to save the generated graph in edge list format (y/n)? ");445fflush(stdin);446scanf(" %c", &saveEdgeListFormat);447if (tolower(saveEdgeListFormat) == 'y')448{449char *fileName = "maxPlanarEdgeList.txt";450if (extraEdges > 0)451fileName = "nonPlanarEdgeList.txt";452453SaveAsciiGraph(theGraph, fileName);454sprintf(Line, "Edge list format saved to '%s'\n", fileName);455Message(Line);456}457}458else ErrorMessage("Failure occurred");459460gp_Free(&theGraph);461gp_Free(&origGraph);462463FlushConsole(stdout);464return Result;465}466467468