int RandomGraphs(char command, int NumGraphs, int SizeOfGraphs) { char theFileName[256]; int K, countUpdateFreq; int Result=OK, MainStatistic=0; int ObstructionMinorFreqs[NUM_MINORS]; graphP theGraph=NULL, origGraph=NULL; platform_time start, end; int embedFlags = GetEmbedFlags(command); int ReuseGraphs = TRUE; GetNumberIfZero(&NumGraphs, "Enter number of graphs to generate:", 1, 1000000000); GetNumberIfZero(&SizeOfGraphs, "Enter size of graphs:", 1, 10000); theGraph = MakeGraph(SizeOfGraphs, command); origGraph = MakeGraph(SizeOfGraphs, command); if (theGraph == NULL || origGraph == NULL) { gp_Free(&theGraph); return NOTOK; } // Initialize a secondary statistics array for (K=0; K < NUM_MINORS; K++) ObstructionMinorFreqs[K] = 0; // Seed the random number generator with "now". Do it after any prompting // to tie randomness to human process of answering the prompt. srand(time(NULL)); // Select a counter update frequency that updates more frequently with larger graphs // and which is relatively prime with 10 so that all digits of the count will change // even though we aren't showing the count value on every iteration countUpdateFreq = 3579 / SizeOfGraphs; countUpdateFreq = countUpdateFreq < 1 ? 1 : countUpdateFreq; countUpdateFreq = countUpdateFreq % 2 == 0 ? countUpdateFreq+1 : countUpdateFreq; countUpdateFreq = countUpdateFreq % 5 == 0 ? countUpdateFreq+2 : countUpdateFreq; // Start the count fprintf(stdout, "0\r"); fflush(stdout); // Start the timer platform_GetTime(start); // Generate and process the number of graphs requested for (K=0; K < NumGraphs; K++) { if ((Result = gp_CreateRandomGraph(theGraph)) == OK) { if (tolower(OrigOut)=='y') { sprintf(theFileName, "random\\%d.txt", K%10); gp_Write(theGraph, theFileName, WRITE_ADJLIST); } gp_CopyGraph(origGraph, theGraph); if (strchr("pdo234", command)) { Result = gp_Embed(theGraph, embedFlags); if (gp_TestEmbedResultIntegrity(theGraph, origGraph, Result) != Result) Result = NOTOK; if (Result == OK) { MainStatistic++; if (tolower(EmbeddableOut) == 'y') { sprintf(theFileName, "embedded\\%d.txt", K%10); gp_Write(theGraph, theFileName, WRITE_ADJMATRIX); } if (tolower(AdjListsForEmbeddingsOut) == 'y') { sprintf(theFileName, "adjlist\\%d.txt", K%10); gp_Write(theGraph, theFileName, WRITE_ADJLIST); } } else if (Result == NONEMBEDDABLE) { if (embedFlags == EMBEDFLAGS_PLANAR || embedFlags == EMBEDFLAGS_OUTERPLANAR) { if (theGraph->IC.minorType & MINORTYPE_A) ObstructionMinorFreqs[0] ++; else if (theGraph->IC.minorType & MINORTYPE_B) ObstructionMinorFreqs[1] ++; else if (theGraph->IC.minorType & MINORTYPE_C) ObstructionMinorFreqs[2] ++; else if (theGraph->IC.minorType & MINORTYPE_D) ObstructionMinorFreqs[3] ++; else if (theGraph->IC.minorType & MINORTYPE_E) ObstructionMinorFreqs[4] ++; if (theGraph->IC.minorType & MINORTYPE_E1) ObstructionMinorFreqs[5] ++; else if (theGraph->IC.minorType & MINORTYPE_E2) ObstructionMinorFreqs[6] ++; else if (theGraph->IC.minorType & MINORTYPE_E3) ObstructionMinorFreqs[7] ++; else if (theGraph->IC.minorType & MINORTYPE_E4) ObstructionMinorFreqs[8] ++; if (tolower(ObstructedOut) == 'y') { sprintf(theFileName, "obstructed\\%d.txt", K%10); gp_Write(theGraph, theFileName, WRITE_ADJMATRIX); } } } } else if (command == 'c') { if ((Result = gp_ColorVertices(theGraph)) == OK) Result = gp_ColorVerticesIntegrityCheck(theGraph, origGraph); if (Result == OK && gp_GetNumColorsUsed(theGraph) <= 5) MainStatistic++; } // If there is an error in processing, then write the file for debugging if (Result != OK && Result != NONEMBEDDABLE) { sprintf(theFileName, "error\\%d.txt", K%10); gp_Write(origGraph, theFileName, WRITE_ADJLIST); } } // Reinitialize or recreate graphs for next iteration ReinitializeGraph(&theGraph, ReuseGraphs, command); ReinitializeGraph(&origGraph, ReuseGraphs, command); // Show progress, but not so often that it bogs down progress if (quietMode == 'n' && (K+1) % countUpdateFreq == 0) { fprintf(stdout, "%d\r", K+1); fflush(stdout); } // Terminate loop on error if (Result != OK && Result != NONEMBEDDABLE) { ErrorMessage("\nError found\n"); Result = NOTOK; break; } } // Stop the timer platform_GetTime(end); // Finish the count fprintf(stdout, "%d\n", NumGraphs); fflush(stdout); // Free the graph structures created before the loop gp_Free(&theGraph); gp_Free(&origGraph); // Print some demographic results if (Result == OK || Result == NONEMBEDDABLE) Message("\nNo Errors Found."); sprintf(Line, "\nDone (%.3lf seconds).\n", platform_GetDuration(start,end)); Message(Line); // Report statistics for planar or outerplanar embedding if (embedFlags == EMBEDFLAGS_PLANAR || embedFlags == EMBEDFLAGS_OUTERPLANAR) { sprintf(Line, "Num Embedded=%d.\n", MainStatistic); Message(Line); for (K=0; K<5; K++) { // Outerplanarity does not produces minors C and D if (embedFlags == EMBEDFLAGS_OUTERPLANAR && (K==2 || K==3)) continue; sprintf(Line, "Minor %c = %d\n", K+'A', ObstructionMinorFreqs[K]); Message(Line); } if (!(embedFlags & ~EMBEDFLAGS_PLANAR)) { sprintf(Line, "\nNote: E1 are added to C, E2 are added to A, and E=E3+E4+K5 homeomorphs.\n"); Message(Line); for (K=5; K<NUM_MINORS; K++) { sprintf(Line, "Minor E%d = %d\n", K-4, ObstructionMinorFreqs[K]); Message(Line); } } } // Report statistics for graph drawing else if (embedFlags == EMBEDFLAGS_DRAWPLANAR) { sprintf(Line, "Num Graphs Embedded and Drawn=%d.\n", MainStatistic); Message(Line); } // Report statistics for subgraph homeomorphism algorithms else if (embedFlags == EMBEDFLAGS_SEARCHFORK23) { sprintf(Line, "Of the generated graphs, %d did not contain a K_{2,3} homeomorph as a subgraph.\n", MainStatistic); Message(Line); } else if (embedFlags == EMBEDFLAGS_SEARCHFORK33) { sprintf(Line, "Of the generated graphs, %d did not contain a K_{3,3} homeomorph as a subgraph.\n", MainStatistic); Message(Line); } else if (embedFlags == EMBEDFLAGS_SEARCHFORK4) { sprintf(Line, "Of the generated graphs, %d did not contain a K_4 homeomorph as a subgraph.\n", MainStatistic); Message(Line); } // Report statistics for vertex coloring else if (command == 'c') { sprintf(Line, "Num Graphs colored with 5 or fewer colors=%d.\n", MainStatistic); Message(Line); } FlushConsole(stdout); return Result==OK || Result==NONEMBEDDABLE ? OK : NOTOK; }
int RandomGraph(char command, int extraEdges, int numVertices, char *outfileName, char *outfile2Name) { int Result; platform_time start, end; graphP theGraph=NULL, origGraph; int embedFlags = GetEmbedFlags(command); char saveEdgeListFormat; GetNumberIfZero(&numVertices, "Enter number of vertices:", 1, 1000000); if ((theGraph = MakeGraph(numVertices, command)) == NULL) return NOTOK; srand(time(NULL)); Message("Creating the random graph...\n"); platform_GetTime(start); if (gp_CreateRandomGraphEx(theGraph, 3*numVertices-6+extraEdges) != OK) { ErrorMessage("gp_CreateRandomGraphEx() failed\n"); return NOTOK; } platform_GetTime(end); sprintf(Line, "Created random graph with %d edges in %.3lf seconds. ", theGraph->M, platform_GetDuration(start,end)); Message(Line); FlushConsole(stdout); // The user may have requested a copy of the random graph before processing if (outfile2Name != NULL) { gp_Write(theGraph, outfile2Name, WRITE_ADJLIST); } origGraph = gp_DupGraph(theGraph); // Do the requested algorithm on the randomly generated graph Message("Now processing\n"); FlushConsole(stdout); if (strchr("pdo234", command)) { platform_GetTime(start); Result = gp_Embed(theGraph, embedFlags); platform_GetTime(end); gp_SortVertices(theGraph); if (gp_TestEmbedResultIntegrity(theGraph, origGraph, Result) != Result) Result = NOTOK; } else if (command == 'c') { platform_GetTime(start); Result = gp_ColorVertices(theGraph); platform_GetTime(end); } else Result = NOTOK; // Write what the algorithm determined and how long it took WriteAlgorithmResults(theGraph, Result, command, start, end, NULL); // On successful algorithm result, write the output file and see if the // user wants the edge list formatted file. if (Result == OK || Result == NONEMBEDDABLE) { if (outfileName != NULL) gp_Write(theGraph, outfileName, WRITE_ADJLIST); Prompt("Do you want to save the generated graph in edge list format (y/n)? "); fflush(stdin); scanf(" %c", &saveEdgeListFormat); if (tolower(saveEdgeListFormat) == 'y') { char *fileName = "maxPlanarEdgeList.txt"; if (extraEdges > 0) fileName = "nonPlanarEdgeList.txt"; SaveAsciiGraph(theGraph, fileName); sprintf(Line, "Edge list format saved to '%s'\n", fileName); Message(Line); } } else ErrorMessage("Failure occurred"); gp_Free(&theGraph); gp_Free(&origGraph); FlushConsole(stdout); return Result; }
int SpecificGraph(char command, char *infileName, char *outfileName, char *outfile2Name) { graphP theGraph, origGraph; platform_time start, end; int Result; // Get the filename of the graph to test if ((infileName = ConstructInputFilename(infileName)) == NULL) return NOTOK; // Create the graph and, if needed, attach the correct algorithm to it theGraph = gp_New(); switch (command) { case 'd' : gp_AttachDrawPlanar(theGraph); break; case '2' : gp_AttachK23Search(theGraph); break; case '3' : gp_AttachK33Search(theGraph); break; case '4' : gp_AttachK4Search(theGraph); break; case 'c' : gp_AttachColorVertices(theGraph); break; } // Read the graph into memory Result = gp_Read(theGraph, infileName); if (Result == NONEMBEDDABLE) { Message("The graph contains too many edges.\n"); // Some of the algorithms will still run correctly with some edges removed. if (strchr("pdo234", command)) { Message("Some edges were removed, but the algorithm will still run correctly.\n"); Result = OK; } } // If there was an unrecoverable error, report it if (Result != OK) ErrorMessage("Failed to read graph\n"); // Otherwise, call the correct algorithm on it else { // Copy the graph for integrity checking origGraph = gp_DupGraph(theGraph); // Run the algorithm if (strchr("pdo234", command)) { int embedFlags = GetEmbedFlags(command); platform_GetTime(start); // gp_CreateDFSTree(theGraph); // gp_SortVertices(theGraph); // gp_Write(theGraph, "debug.before.txt", WRITE_DEBUGINFO); // gp_SortVertices(theGraph); Result = gp_Embed(theGraph, embedFlags); platform_GetTime(end); Result = gp_TestEmbedResultIntegrity(theGraph, origGraph, Result); } else { platform_GetTime(start); if (command == 'c') { if ((Result = gp_ColorVertices(theGraph)) == OK) Result = gp_ColorVerticesIntegrityCheck(theGraph, origGraph); } else Result = NOTOK; platform_GetTime(end); } // Write what the algorithm determined and how long it took WriteAlgorithmResults(theGraph, Result, command, start, end, infileName); // Free the graph obtained for integrity checking. gp_Free(&origGraph); } // Report an error, if there was one, free the graph, and return if (Result != OK && Result != NONEMBEDDABLE) { ErrorMessage("AN ERROR HAS BEEN DETECTED\n"); Result = NOTOK; // gp_Write(theGraph, "debug.after.txt", WRITE_DEBUGINFO); } // Provide the output file(s) else { // Restore the vertex ordering of the original graph (undo DFS numbering) if (strchr("pdo234", command)) gp_SortVertices(theGraph); // Determine the name of the primary output file outfileName = ConstructPrimaryOutputFilename(infileName, outfileName, command); // For some algorithms, the primary output file is not always written if ((strchr("pdo", command) && Result == NONEMBEDDABLE) || (strchr("234", command) && Result == OK)) { // Do not write the file } // Write the primary output file, if appropriate to do so else { gp_Write(theGraph, outfileName, WRITE_ADJLIST); } // NOW WE WANT TO WRITE THE SECONDARY OUTPUT FILE // When called from the menu system, we want to write the planar or outerplanar // obstruction, if one exists. For planar graph drawing, we want the character // art rendition. An empty but non-NULL string is passed to indicate the necessity // of selecting a default name for the second output file. if (outfile2Name != NULL) { if ((command == 'p' || command == 'o') && Result == NONEMBEDDABLE) { // By default, use the same name as the primary output filename if (strlen(outfile2Name) == 0) outfile2Name = outfileName; gp_Write(theGraph, outfile2Name, WRITE_ADJLIST); } else if (command == 'd' && Result == OK) { // By default, add ".render.txt" to the primary output filename if (strlen(outfile2Name) == 0) strcat((outfile2Name = outfileName), ".render.txt"); gp_DrawPlanar_RenderToFile(theGraph, outfile2Name); } } } // Free the graph gp_Free(&theGraph); // Flush any remaining message content to the user, and return the result FlushConsole(stdout); return Result; }
int gp_CreateDFSTree(graphP theGraph) { stackP theStack; int N, DFI = 0, I, uparent, u, e, J; #ifdef PROFILE platform_time start, end; platform_GetTime(start); #endif if (theGraph==NULL) return NOTOK; if (theGraph->internalFlags & FLAGS_DFSNUMBERED) return OK; gp_LogLine("\ngraphPreprocess.c/gp_CreateDFSTree() start"); N = theGraph->N; theStack = theGraph->theStack; /* There are 2M edge records (arcs) and for each we can push 2 integers, so a stack of 2 * arcCapacity integers suffices. This is already in theGraph structure, so we make sure it's empty, then clear all visited flags in prep for the Depth first search. */ if (sp_GetCapacity(theStack) < 2*gp_GetArcCapacity(theGraph)) return NOTOK; sp_ClearStack(theStack); for (I=0; I < N; I++) theGraph->G[I].visited = 0; /* This outer loop causes the connected subgraphs of a disconnected graph to be numbered */ for (I=0; I < N && DFI < N; I++) { if (theGraph->V[I].DFSParent != NIL) continue; sp_Push2(theStack, NIL, NIL); while (sp_NonEmpty(theStack)) { sp_Pop2(theStack, uparent, e); u = uparent == NIL ? I : theGraph->G[e].v; if (!theGraph->G[u].visited) { gp_LogLine(gp_MakeLogStr3("V=%d, DFI=%d, Parent=%d", u, DFI, uparent)); theGraph->G[u].visited = 1; theGraph->G[u].v = DFI++; theGraph->V[u].DFSParent = uparent; if (e != NIL) { theGraph->G[e].type = EDGE_DFSCHILD; theGraph->G[gp_GetTwinArc(theGraph, e)].type = EDGE_DFSPARENT; // We want the child arcs to be at the beginning // of the adjacency list. gp_MoveArcToFirst(theGraph, uparent, e); } /* Push edges to all unvisited neighbors. These will be either tree edges to children or forward arcs of back edges */ J = gp_GetFirstArc(theGraph, u); while (gp_IsArc(theGraph, J)) { if (!theGraph->G[theGraph->G[J].v].visited) sp_Push2(theStack, u, J); J = gp_GetNextArc(theGraph, J); } } else { // If the edge leads to a visited vertex, then it is // the forward arc of a back edge. theGraph->G[e].type = EDGE_FORWARD; theGraph->G[gp_GetTwinArc(theGraph, e)].type = EDGE_BACK; // We want all of the forward edges to descendants to // be at the end of the adjacency list. // The tree edge to the parent and the back edges to ancestors // are in the middle, between the child edges and forward edges. gp_MoveArcToLast(theGraph, uparent, e); } } } gp_LogLine("graphPreprocess.c/gp_CreateDFSTree() end\n"); theGraph->internalFlags |= FLAGS_DFSNUMBERED; #ifdef PROFILE platform_GetTime(end); printf("DFS in %.3lf seconds.\n", platform_GetDuration(start,end)); #endif return OK; }
int gp_LowpointAndLeastAncestor(graphP theGraph) { stackP theStack = theGraph->theStack; int I, u, uneighbor, J, L, leastAncestor; int totalVisited = 0; #ifdef PROFILE platform_time start, end; platform_GetTime(start); #endif sp_ClearStack(theStack); for (I=0; I < theGraph->N; I++) theGraph->G[I].visited = 0; /* This outer loop causes the connected subgraphs of a disconnected graph to be processed */ for (I=0; I < theGraph->N && totalVisited < theGraph->N; I++) { if (theGraph->G[I].visited) continue; sp_Push(theStack, I); while (sp_NonEmpty(theStack)) { sp_Pop(theStack, u); if (!theGraph->G[u].visited) { /* Mark u as visited, then push it back on the stack */ theGraph->G[u].visited = 1; totalVisited++; sp_Push(theStack, u); /* Push DFS children */ J = gp_GetFirstArc(theGraph, u); while (gp_IsArc(theGraph, J)) { if (theGraph->G[J].type == EDGE_DFSCHILD) { sp_Push(theStack, theGraph->G[J].v); } else break; J = gp_GetNextArc(theGraph, J); } } else { /* Start with high values because we are doing a min function */ L = leastAncestor = u; /* Compute L and leastAncestor */ J = gp_GetFirstArc(theGraph, u); while (gp_IsArc(theGraph, J)) { uneighbor = theGraph->G[J].v; if (theGraph->G[J].type == EDGE_DFSCHILD) { if (L > theGraph->V[uneighbor].Lowpoint) L = theGraph->V[uneighbor].Lowpoint; } else if (theGraph->G[J].type == EDGE_BACK) { if (leastAncestor > uneighbor) leastAncestor = uneighbor; } else if (theGraph->G[J].type == EDGE_FORWARD) break; J = gp_GetNextArc(theGraph, J); } /* Assign leastAncestor and Lowpoint to the vertex */ theGraph->V[u].leastAncestor = leastAncestor; theGraph->V[u].Lowpoint = leastAncestor < L ? leastAncestor : L; } } } #ifdef PROFILE platform_GetTime(end); printf("Lowpoint in %.3lf seconds.\n", platform_GetDuration(start,end)); #endif return OK; }
int _SortVertices(graphP theGraph) { int I, N, M, e, J, srcPos, dstPos; vertexRec tempV; graphNode tempG; #ifdef PROFILE platform_time start, end; platform_GetTime(start); #endif if (theGraph == NULL) return NOTOK; if (!(theGraph->internalFlags&FLAGS_DFSNUMBERED)) if (gp_CreateDFSTree(theGraph) != OK) return NOTOK; /* Cache number of vertices and edges into local variables */ N = theGraph->N; M = theGraph->M + sp_GetCurrentSize(theGraph->edgeHoles); /* Change labels of edges from v to DFI(v)-- or vice versa Also, if any links go back to locations 0 to n-1, then they need to be changed because we are reordering the vertices */ for (e=0, J=theGraph->edgeOffset; e < M; e++, J+=2) { if (theGraph->G[J].v != NIL) { theGraph->G[J].v = theGraph->G[theGraph->G[J].v].v; theGraph->G[J+1].v = theGraph->G[theGraph->G[J+1].v].v; } } /* Convert DFSParent from v to DFI(v) or vice versa */ for (I=0; I < N; I++) if (theGraph->V[I].DFSParent != NIL) theGraph->V[I].DFSParent = theGraph->G[theGraph->V[I].DFSParent].v; /* Sort by 'v using constant time random access. Move each vertex to its destination 'v', and store its source location in 'v'. */ /* First we clear the visitation flags. We need these to help mark visited vertices because we change the 'v' field to be the source location, so we cannot use index==v as a test for whether the correct vertex is in location 'index'. */ for (I=0; I < N; I++) theGraph->G[I].visited = 0; /* We visit each vertex location, skipping those marked as visited since we've already moved the correct vertex into that location. The inner loop swaps the vertex at location I into the correct position, G[I].v, marks that location as visited, then sets its 'v' field to be the location from whence we obtained the vertex record. */ for (I=0; I < N; I++) { srcPos = I; while (!theGraph->G[I].visited) { dstPos = theGraph->G[I].v; tempG = theGraph->G[dstPos]; tempV = theGraph->V[dstPos]; theGraph->G[dstPos] = theGraph->G[I]; theGraph->V[dstPos] = theGraph->V[I]; theGraph->G[I] = tempG; theGraph->V[I] = tempV; theGraph->G[dstPos].visited = 1; theGraph->G[dstPos].v = srcPos; srcPos = dstPos; } } /* Invert the bit that records the sort order of the graph */ if (theGraph->internalFlags & FLAGS_SORTEDBYDFI) theGraph->internalFlags &= ~FLAGS_SORTEDBYDFI; else theGraph->internalFlags |= FLAGS_SORTEDBYDFI; #ifdef PROFILE platform_GetTime(end); printf("SortVertices in %.3lf seconds.\n", platform_GetDuration(start,end)); #endif return OK; }