Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/graphs/planarity/planarityRandomGraphs.c
4057 views
1
/*
2
Planarity-Related Graph Algorithms Project
3
Copyright (c) 1997-2010, John M. Boyer
4
All rights reserved. Includes a reference implementation of the following:
5
6
* John M. Boyer. "Simplified O(n) Algorithms for Planar Graph Embedding,
7
Kuratowski Subgraph Isolation, and Related Problems". Ph.D. Dissertation,
8
University of Victoria, 2001.
9
10
* John M. Boyer and Wendy J. Myrvold. "On the Cutting Edge: Simplified O(n)
11
Planarity by Edge Addition". Journal of Graph Algorithms and Applications,
12
Vol. 8, No. 3, pp. 241-273, 2004.
13
14
* John M. Boyer. "A New Method for Efficiently Generating Planar Graph
15
Visibility Representations". In P. Eades and P. Healy, editors,
16
Proceedings of the 13th International Conference on Graph Drawing 2005,
17
Lecture Notes Comput. Sci., Volume 3843, pp. 508-511, Springer-Verlag, 2006.
18
19
Redistribution and use in source and binary forms, with or without modification,
20
are permitted provided that the following conditions are met:
21
22
* Redistributions of source code must retain the above copyright notice, this
23
list of conditions and the following disclaimer.
24
25
* Redistributions in binary form must reproduce the above copyright notice, this
26
list of conditions and the following disclaimer in the documentation and/or
27
other materials provided with the distribution.
28
29
* Neither the name of the Planarity-Related Graph Algorithms Project nor the names
30
of its contributors may be used to endorse or promote products derived from this
31
software without specific prior written permission.
32
33
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
34
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
37
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
39
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
40
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
41
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
42
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43
*/
44
45
#include "planarity.h"
46
47
void GetNumberIfZero(int *pNum, char *prompt, int min, int max);
48
void ReinitializeGraph(graphP *pGraph, int ReuseGraphs, char command);
49
graphP MakeGraph(int Size, char command);
50
51
/****************************************************************************
52
RandomGraphs()
53
Top-level method to randomly generate graphs to test the algorithm given by
54
the command parameter.
55
The number of graphs to generate, and the number of vertices for each graph,
56
can be sent as the second and third params. For each that is sent as zero,
57
this method will prompt the user for a value.
58
****************************************************************************/
59
60
#define NUM_MINORS 9
61
62
int RandomGraphs(char command, int NumGraphs, int SizeOfGraphs)
63
{
64
char theFileName[256];
65
int I, countUpdateFreq;
66
int Result=OK, MainStatistic=0;
67
int ObstructionMinorFreqs[NUM_MINORS];
68
graphP theGraph=NULL, origGraph=NULL;
69
platform_time start, end;
70
int embedFlags = GetEmbedFlags(command);
71
int ReuseGraphs = TRUE;
72
73
GetNumberIfZero(&NumGraphs, "Enter number of graphs to generate:", 1, 1000000000);
74
GetNumberIfZero(&SizeOfGraphs, "Enter size of graphs:", 1, 10000);
75
76
theGraph = MakeGraph(SizeOfGraphs, command);
77
origGraph = MakeGraph(SizeOfGraphs, command);
78
if (theGraph == NULL || origGraph == NULL)
79
{
80
gp_Free(&theGraph);
81
return NOTOK;
82
}
83
84
// Initialize a secondary statistics array
85
for (I=0; I<NUM_MINORS; I++)
86
ObstructionMinorFreqs[I] = 0;
87
88
// Seed the random number generator with "now". Do it after any prompting
89
// to tie randomness to human process of answering the prompt.
90
srand(time(NULL));
91
92
// Select a counter update frequency that updates more frequently with larger graphs
93
// and which is relatively prime with 10 so that all digits of the count will change
94
// even though we aren't showing the count value on every iteration
95
countUpdateFreq = 3579 / SizeOfGraphs;
96
countUpdateFreq = countUpdateFreq < 1 ? 1 : countUpdateFreq;
97
countUpdateFreq = countUpdateFreq % 2 == 0 ? countUpdateFreq+1 : countUpdateFreq;
98
countUpdateFreq = countUpdateFreq % 5 == 0 ? countUpdateFreq+2 : countUpdateFreq;
99
100
// Start the count
101
fprintf(stdout, "0\r");
102
fflush(stdout);
103
104
// Start the timer
105
platform_GetTime(start);
106
107
// Generate and process the number of graphs requested
108
for (I=0; I < NumGraphs; I++)
109
{
110
if ((Result = gp_CreateRandomGraph(theGraph)) == OK)
111
{
112
if (tolower(OrigOut)=='y')
113
{
114
sprintf(theFileName, "random\\%d.txt", I%10);
115
gp_Write(theGraph, theFileName, WRITE_ADJLIST);
116
}
117
118
gp_CopyGraph(origGraph, theGraph);
119
120
if (strchr("pdo234", command))
121
{
122
Result = gp_Embed(theGraph, embedFlags);
123
124
if (gp_TestEmbedResultIntegrity(theGraph, origGraph, Result) != Result)
125
Result = NOTOK;
126
127
if (Result == OK)
128
{
129
MainStatistic++;
130
131
if (tolower(EmbeddableOut) == 'y')
132
{
133
sprintf(theFileName, "embedded\\%d.txt", I%10);
134
gp_Write(theGraph, theFileName, WRITE_ADJMATRIX);
135
}
136
137
if (tolower(AdjListsForEmbeddingsOut) == 'y')
138
{
139
sprintf(theFileName, "adjlist\\%d.txt", I%10);
140
gp_Write(theGraph, theFileName, WRITE_ADJLIST);
141
}
142
}
143
else if (Result == NONEMBEDDABLE)
144
{
145
if (embedFlags == EMBEDFLAGS_PLANAR || embedFlags == EMBEDFLAGS_OUTERPLANAR)
146
{
147
if (theGraph->IC.minorType & MINORTYPE_A)
148
ObstructionMinorFreqs[0] ++;
149
else if (theGraph->IC.minorType & MINORTYPE_B)
150
ObstructionMinorFreqs[1] ++;
151
else if (theGraph->IC.minorType & MINORTYPE_C)
152
ObstructionMinorFreqs[2] ++;
153
else if (theGraph->IC.minorType & MINORTYPE_D)
154
ObstructionMinorFreqs[3] ++;
155
else if (theGraph->IC.minorType & MINORTYPE_E)
156
ObstructionMinorFreqs[4] ++;
157
158
if (theGraph->IC.minorType & MINORTYPE_E1)
159
ObstructionMinorFreqs[5] ++;
160
else if (theGraph->IC.minorType & MINORTYPE_E2)
161
ObstructionMinorFreqs[6] ++;
162
else if (theGraph->IC.minorType & MINORTYPE_E3)
163
ObstructionMinorFreqs[7] ++;
164
else if (theGraph->IC.minorType & MINORTYPE_E4)
165
ObstructionMinorFreqs[8] ++;
166
167
if (tolower(ObstructedOut) == 'y')
168
{
169
sprintf(theFileName, "obstructed\\%d.txt", I%10);
170
gp_Write(theGraph, theFileName, WRITE_ADJMATRIX);
171
}
172
}
173
}
174
}
175
else if (command == 'c')
176
{
177
if ((Result = gp_ColorVertices(theGraph)) == OK)
178
Result = gp_ColorVerticesIntegrityCheck(theGraph, origGraph);
179
if (Result == OK && gp_GetNumColorsUsed(theGraph) <= 5)
180
MainStatistic++;
181
}
182
183
// If there is an error in processing, then write the file for debugging
184
if (Result != OK && Result != NONEMBEDDABLE)
185
{
186
sprintf(theFileName, "error\\%d.txt", I%10);
187
gp_Write(origGraph, theFileName, WRITE_ADJLIST);
188
}
189
}
190
191
// Reinitialize or recreate graphs for next iteration
192
ReinitializeGraph(&theGraph, ReuseGraphs, command);
193
ReinitializeGraph(&origGraph, ReuseGraphs, command);
194
195
// Show progress, but not so often that it bogs down progress
196
if (quietMode == 'n' && (I+1) % countUpdateFreq == 0)
197
{
198
fprintf(stdout, "%d\r", I+1);
199
fflush(stdout);
200
}
201
202
// Terminate loop on error
203
if (Result != OK && Result != NONEMBEDDABLE)
204
{
205
ErrorMessage("\nError found\n");
206
Result = NOTOK;
207
break;
208
}
209
}
210
211
// Stop the timer
212
platform_GetTime(end);
213
214
// Finish the count
215
fprintf(stdout, "%d\n", NumGraphs);
216
fflush(stdout);
217
218
// Free the graph structures created before the loop
219
gp_Free(&theGraph);
220
gp_Free(&origGraph);
221
222
// Print some demographic results
223
if (Result == OK || Result == NONEMBEDDABLE)
224
Message("\nNo Errors Found.");
225
sprintf(Line, "\nDone (%.3lf seconds).\n", platform_GetDuration(start,end));
226
Message(Line);
227
228
// Report statistics for planar or outerplanar embedding
229
if (embedFlags == EMBEDFLAGS_PLANAR || embedFlags == EMBEDFLAGS_OUTERPLANAR)
230
{
231
sprintf(Line, "Num Embedded=%d.\n", MainStatistic);
232
Message(Line);
233
234
for (I=0; I<5; I++)
235
{
236
// Outerplanarity does not produces minors C and D
237
if (embedFlags == EMBEDFLAGS_OUTERPLANAR && (I==2 || I==3))
238
continue;
239
240
sprintf(Line, "Minor %c = %d\n", I+'A', ObstructionMinorFreqs[I]);
241
Message(Line);
242
}
243
244
if (!(embedFlags & ~EMBEDFLAGS_PLANAR))
245
{
246
sprintf(Line, "\nNote: E1 are added to C, E2 are added to A, and E=E3+E4+K5 homeomorphs.\n");
247
Message(Line);
248
249
for (I=5; I<NUM_MINORS; I++)
250
{
251
sprintf(Line, "Minor E%d = %d\n", I-4, ObstructionMinorFreqs[I]);
252
Message(Line);
253
}
254
}
255
}
256
257
// Report statistics for graph drawing
258
else if (embedFlags == EMBEDFLAGS_DRAWPLANAR)
259
{
260
sprintf(Line, "Num Graphs Embedded and Drawn=%d.\n", MainStatistic);
261
Message(Line);
262
}
263
264
// Report statistics for subgraph homeomorphism algorithms
265
else if (embedFlags == EMBEDFLAGS_SEARCHFORK23)
266
{
267
sprintf(Line, "Of the generated graphs, %d did not contain a K_{2,3} homeomorph as a subgraph.\n", MainStatistic);
268
Message(Line);
269
}
270
else if (embedFlags == EMBEDFLAGS_SEARCHFORK33)
271
{
272
sprintf(Line, "Of the generated graphs, %d did not contain a K_{3,3} homeomorph as a subgraph.\n", MainStatistic);
273
Message(Line);
274
}
275
else if (embedFlags == EMBEDFLAGS_SEARCHFORK4)
276
{
277
sprintf(Line, "Of the generated graphs, %d did not contain a K_4 homeomorph as a subgraph.\n", MainStatistic);
278
Message(Line);
279
}
280
281
// Report statistics for vertex coloring
282
else if (command == 'c')
283
{
284
sprintf(Line, "Num Graphs colored with 5 or fewer colors=%d.\n", MainStatistic);
285
Message(Line);
286
}
287
288
FlushConsole(stdout);
289
290
return Result==OK || Result==NONEMBEDDABLE ? OK : NOTOK;
291
}
292
293
/****************************************************************************
294
GetNumberIfZero()
295
Internal function that gets a number if the given *pNum is zero.
296
The prompt is displayed if the number must be obtained from the user.
297
Whether the given number is used or obtained from the user, the function
298
ensures it is in the range [min, max] and assigns the midpoint value if
299
it is not.
300
****************************************************************************/
301
302
void GetNumberIfZero(int *pNum, char *prompt, int min, int max)
303
{
304
if (*pNum == 0)
305
{
306
Prompt(prompt);
307
scanf(" %d", pNum);
308
}
309
310
if (min < 1) min = 1;
311
if (max < min) max = min;
312
313
if (*pNum < min || *pNum > max)
314
{
315
*pNum = (max + min) / 2;
316
sprintf(Line, "Number out of range [%d, %d]; changed to %d\n", min, max, *pNum);
317
ErrorMessage(Line);
318
}
319
}
320
321
/****************************************************************************
322
MakeGraph()
323
Internal function that makes a new graph, initializes it, and attaches an
324
algorithm to it based on the command.
325
****************************************************************************/
326
327
graphP MakeGraph(int Size, char command)
328
{
329
graphP theGraph;
330
if ((theGraph = gp_New()) == NULL || gp_InitGraph(theGraph, Size) != OK)
331
{
332
ErrorMessage("Error creating space for a graph of the given size.\n");
333
gp_Free(&theGraph);
334
return NULL;
335
}
336
337
// Enable the appropriate feature. Although the same code appears in SpecificGraph,
338
// it is deliberately not separated to a common utility because SpecificGraph is
339
// used as a self-contained tutorial. It is not that hard to update both locations
340
// when new algorithms are added.
341
342
switch (command)
343
{
344
case 'd' : gp_AttachDrawPlanar(theGraph); break;
345
case '2' : gp_AttachK23Search(theGraph); break;
346
case '3' : gp_AttachK33Search(theGraph); break;
347
case '4' : gp_AttachK4Search(theGraph); break;
348
case 'c' : gp_AttachColorVertices(theGraph); break;
349
}
350
351
return theGraph;
352
}
353
354
/****************************************************************************
355
ReinitializeGraph()
356
Internal function that will either reinitialize the given graph or free it
357
and make a new one just like it.
358
****************************************************************************/
359
360
void ReinitializeGraph(graphP *pGraph, int ReuseGraphs, char command)
361
{
362
if (ReuseGraphs)
363
gp_ReinitializeGraph(*pGraph);
364
else
365
{
366
graphP newGraph = MakeGraph((*pGraph)->N, command);
367
gp_Free(pGraph);
368
*pGraph = newGraph;
369
}
370
}
371
372
/****************************************************************************
373
Creates a random maximal planar graph, then adds 'extraEdges' edges to it.
374
****************************************************************************/
375
376
int RandomGraph(char command, int extraEdges, int numVertices, char *outfileName, char *outfile2Name)
377
{
378
int Result;
379
platform_time start, end;
380
graphP theGraph=NULL, origGraph;
381
int embedFlags = GetEmbedFlags(command);
382
char saveEdgeListFormat;
383
384
GetNumberIfZero(&numVertices, "Enter number of vertices:", 1, 1000000);
385
if ((theGraph = MakeGraph(numVertices, command)) == NULL)
386
return NOTOK;
387
388
srand(time(NULL));
389
390
Message("Creating the random graph...\n");
391
platform_GetTime(start);
392
if (gp_CreateRandomGraphEx(theGraph, 3*numVertices-6+extraEdges) != OK)
393
{
394
ErrorMessage("gp_CreateRandomGraphEx() failed\n");
395
return NOTOK;
396
}
397
platform_GetTime(end);
398
399
sprintf(Line, "Created random graph with %d edges in %.3lf seconds. ", theGraph->M, platform_GetDuration(start,end));
400
Message(Line);
401
FlushConsole(stdout);
402
403
// The user may have requested a copy of the random graph before processing
404
if (outfile2Name != NULL)
405
{
406
gp_Write(theGraph, outfile2Name, WRITE_ADJLIST);
407
}
408
409
origGraph = gp_DupGraph(theGraph);
410
411
// Do the requested algorithm on the randomly generated graph
412
Message("Now processing\n");
413
FlushConsole(stdout);
414
415
if (strchr("pdo234", command))
416
{
417
platform_GetTime(start);
418
Result = gp_Embed(theGraph, embedFlags);
419
platform_GetTime(end);
420
421
gp_SortVertices(theGraph);
422
423
if (gp_TestEmbedResultIntegrity(theGraph, origGraph, Result) != Result)
424
Result = NOTOK;
425
}
426
else if (command == 'c')
427
{
428
platform_GetTime(start);
429
Result = gp_ColorVertices(theGraph);
430
platform_GetTime(end);
431
}
432
else
433
Result = NOTOK;
434
435
// Write what the algorithm determined and how long it took
436
WriteAlgorithmResults(theGraph, Result, command, start, end, NULL);
437
438
// On successful algorithm result, write the output file and see if the
439
// user wants the edge list formatted file.
440
if (Result == OK || Result == NONEMBEDDABLE)
441
{
442
if (outfileName != NULL)
443
gp_Write(theGraph, outfileName, WRITE_ADJLIST);
444
445
Prompt("Do you want to save the generated graph in edge list format (y/n)? ");
446
fflush(stdin);
447
scanf(" %c", &saveEdgeListFormat);
448
if (tolower(saveEdgeListFormat) == 'y')
449
{
450
char *fileName = "maxPlanarEdgeList.txt";
451
if (extraEdges > 0)
452
fileName = "nonPlanarEdgeList.txt";
453
454
SaveAsciiGraph(theGraph, fileName);
455
sprintf(Line, "Edge list format saved to '%s'\n", fileName);
456
Message(Line);
457
}
458
}
459
else ErrorMessage("Failure occurred");
460
461
gp_Free(&theGraph);
462
gp_Free(&origGraph);
463
464
FlushConsole(stdout);
465
return Result;
466
}
467
468