int _ReadAdjMatrix(graphP theGraph, FILE *Infile) { int N, I, W, Flag, ErrorCode; if (Infile == NULL) return NOTOK; fscanf(Infile, " %d ", &N); if (gp_InitGraph(theGraph, N) != OK) return NOTOK; for (I = 0, ErrorCode = OK; I < N-1 && ErrorCode==OK; I++) { theGraph->G[I].v = I; for (W = I+1; W < N; W++) { fscanf(Infile, " %1d", &Flag); if (Flag) { ErrorCode = gp_AddEdge(theGraph, I, 0, W, 0); if (ErrorCode != OK) break; } } } return ErrorCode; }
graphP MakeGraph(int Size, char command) { graphP theGraph; if ((theGraph = gp_New()) == NULL || gp_InitGraph(theGraph, Size) != OK) { ErrorMessage("Error creating space for a graph of the given size.\n"); gp_Free(&theGraph); return NULL; } // Enable the appropriate feature. Although the same code appears in SpecificGraph, // it is deliberately not separated to a common utility because SpecificGraph is // used as a self-contained tutorial. It is not that hard to update both locations // when new algorithms are added. 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; } return theGraph; }
int _ReadLEDAGraph(graphP theGraph, FILE *Infile) { char Line[256]; int N, I, M, J, u, v; /* Skip the lines that say LEDA.GRAPH and give the node and edge types */ fgets(Line, 255, Infile); fgets(Line, 255, Infile); fgets(Line, 255, Infile); /* Read the number of vertices, then skip that many more lines. */ fgets(Line, 255, Infile); sscanf(Line, " %d", &N); for (I = 0; I < N; I++) fgets(Line, 255, Infile); /* Initialize the graph */ if (gp_InitGraph(theGraph, N) != OK) return NOTOK; /* Read the number of edges */ fgets(Line, 255, Infile); sscanf(Line, " %d", &M); /* Read and add each edge, omitting duplicates */ for (J = 0; J < M; J++) { fgets(Line, 255, Infile); sscanf(Line, " %d %d", &u, &v); if (u != v && !gp_IsNeighbor(theGraph, u-1, v-1)) { if (gp_AddEdge(theGraph, u-1, 0, v-1, 0) != OK) return NOTOK; } } return OK; }
int _ReadAdjList(graphP theGraph, FILE *Infile) { int N, I, W, ErrorCode, adjList, J; if (Infile == NULL) return NOTOK; fgetc(Infile); /* Skip the N= */ fgetc(Infile); fscanf(Infile, " %d ", &N); /* Read N */ if (gp_InitGraph(theGraph, N) != OK) { printf("Failed to init graph"); return NOTOK; } // Clear the visited members of the vertices so they can be used // during the adjacency list read operation for (I=0; I < N; I++) theGraph->G[I].visited = 0; // Do the adjacency list read operation for each vertex in order for (I = 0, ErrorCode = OK; I < N && ErrorCode==OK; I++) { // Read the vertex number fscanf(Infile, "%d", &theGraph->G[I].v); // The vertices are expected to be in numeric ascending order if (theGraph->G[I].v != I) return NOTOK; // Skip the colon after the vertex number fgetc(Infile); // If the vertex already has a non-empty adjacency list, then it is // the result of adding edges during processing of preceding vertices. // The list is removed from the current vertex I and saved for use // during the read operation for I. Adjacencies to preceding vertices // are pulled from this list, if present, or added as directed edges // if not. Adjacencies to succeeding vertices are added as undirected // edges, and will be corrected later if the succeeding vertex does not // have the matching adjacency using the following mechanism. After the // read operation for a vertex I, any adjacency nodes left in the saved // list are converted to directed edges from the preceding vertex to I. adjList = gp_GetFirstArc(theGraph, I); if (gp_IsArc(theGraph, adjList)) { // Store the adjacency node location in the visited member of each // of the preceding vertices to which I is adjacent so that we can // efficiently detect the adjacency during the read operation and // efficiently find the adjacency node. J = gp_GetFirstArc(theGraph, I); while (gp_IsArc(theGraph, J)) { theGraph->G[theGraph->G[J].v].visited = J; J = gp_GetNextArc(theGraph, J); } // Make the adjacency list circular, for later ease of processing gp_SetPrevArc(theGraph, adjList, gp_GetLastArc(theGraph, I)); gp_SetNextArc(theGraph, gp_GetLastArc(theGraph, I), adjList); // Remove the list from the vertex gp_SetFirstArc(theGraph, I, gp_AdjacencyListEndMark(I)); gp_SetLastArc(theGraph, I, gp_AdjacencyListEndMark(I)); } // Read the adjacency list. while (1) { // Read the next adjacent vertex, with NIL indicating the list end fscanf(Infile, " %d ", &W); if (W < 0) break; // Vertex numbers must be less than N if (W >= N) ErrorCode = NOTOK; // Loop edges are not supported, but no reason to throw an error if they occur // If a loop occurs, we just do like the ostrich and ignore it else if (W == I) ErrorCode = OK; // If the adjacency is to a succeeding, higher numbered vertex, // then we'll add an undirected edge for now else if (I < W) { ErrorCode = gp_AddEdge(theGraph, I, 0, W, 0); } // If the adjacency is to a preceding, lower numbered vertex, then // we have to pull the adjacency node from the preexisting adjList, // if it is there, and if not then we have to add a directed edge. else { // If the adjacency node (arc) already exists, then we add it // as the new first arc of the vertex and delete it from adjList if (theGraph->G[W].visited) { J = theGraph->G[W].visited; // Remove the arc J from the adjList construct theGraph->G[W].visited = 0; if (adjList == J) { if ((adjList = gp_GetNextArc(theGraph, J)) == J) adjList = NIL; } gp_SetPrevArc(theGraph, gp_GetNextArc(theGraph, J), gp_GetPrevArc(theGraph, J)); gp_SetNextArc(theGraph, gp_GetPrevArc(theGraph, J), gp_GetNextArc(theGraph, J)); gp_AttachFirstArc(theGraph, I, J); } // If an adjacency node to the lower numbered vertex W does not // already exist, then we make a new directed arc from the current // vertex I to W. else { // It is added as the new first arc in both vertices ErrorCode = gp_AddEdge(theGraph, I, 0, W, 0); if (ErrorCode == OK) // Note that this call also sets OUTONLY on the twin arc gp_SetDirection(theGraph, gp_GetFirstArc(theGraph, W), EDGEFLAG_DIRECTION_INONLY); } } if (ErrorCode != OK) break; } // If there are still adjList entries after the read operation // then those entries are not representative of full undirected edges. // Rather, they represent incoming directed arcs from other vertices // into vertex I. They need to be added back into I's adjacency list but // marked as "INONLY", while the twin is marked "OUTONLY" (by the same function). while (gp_IsArc(theGraph, adjList)) { J = adjList; theGraph->G[theGraph->G[J].v].visited = 0; if ((adjList = gp_GetNextArc(theGraph, J)) == J) adjList = NIL; gp_SetPrevArc(theGraph, gp_GetNextArc(theGraph, J), gp_GetPrevArc(theGraph, J)); gp_SetNextArc(theGraph, gp_GetPrevArc(theGraph, J), gp_GetNextArc(theGraph, J)); gp_AttachFirstArc(theGraph, I, J); gp_SetDirection(theGraph, J, EDGEFLAG_DIRECTION_INONLY); } } return ErrorCode; }
Obj boyers_planarity_check(Obj digraph, int flags, bool krtwsk) { DIGRAPHS_ASSERT(flags == EMBEDFLAGS_PLANAR || flags == EMBEDFLAGS_OUTERPLANAR || flags == EMBEDFLAGS_SEARCHFORK23 || flags == EMBEDFLAGS_SEARCHFORK4 || flags == EMBEDFLAGS_SEARCHFORK33); if (CALL_1ARGS(IsDigraph, digraph) != True) { ErrorQuit("Digraphs: boyers_planarity_check (C): the 1st argument must be " "a digraph, not %s", (Int) TNAM_OBJ(digraph), 0L); } Obj const out = FuncOutNeighbours(0L, digraph); if (FuncIS_ANTISYMMETRIC_DIGRAPH(0L, out) != True) { ErrorQuit("Digraphs: boyers_planarity_check (C): the 1st argument must be " "an antisymmetric digraph", 0L, 0L); } Int V = DigraphNrVertices(digraph); Int E = DigraphNrEdges(digraph); if (V > INT_MAX) { // Cannot currently test this, it might always be true, depending on the // definition of Int. ErrorQuit("Digraphs: boyers_planarity_check (C): the maximum number of " "nodes is %d, found %d", INT_MAX, V); return 0L; } else if (2 * E > INT_MAX) { // Cannot currently test this ErrorQuit("Digraphs: boyers_planarity_check (C): the maximum number of " "edges is %d, found %d", INT_MAX / 2, E); return 0L; } graphP theGraph = gp_New(); switch (flags) { case EMBEDFLAGS_SEARCHFORK33: gp_AttachK33Search(theGraph); break; case EMBEDFLAGS_SEARCHFORK23: gp_AttachK23Search(theGraph); break; case EMBEDFLAGS_SEARCHFORK4: gp_AttachK4Search(theGraph); break; } if (gp_InitGraph(theGraph, V) != OK) { gp_Free(&theGraph); ErrorQuit("Digraphs: boyers_planarity_check (C): invalid number of nodes!", 0L, 0L); return 0L; } else if (gp_EnsureArcCapacity(theGraph, 2 * E) != OK) { gp_Free(&theGraph); ErrorQuit("Digraphs: boyers_planarity_check (C): invalid number of edges!", 0L, 0L); return 0L; } int status; for (Int v = 1; v <= LEN_LIST(out); ++v) { DIGRAPHS_ASSERT(gp_VertexInRange(theGraph, v)); gp_SetVertexIndex(theGraph, v, v); Obj const out_v = ELM_LIST(out, v); for (Int w = 1; w <= LEN_LIST(out_v); ++w) { DIGRAPHS_ASSERT(gp_VertexInRange(theGraph, w)); int u = INT_INTOBJ(ELM_LIST(out_v, w)); if (v != u) { status = gp_AddEdge(theGraph, v, 0, u, 0); if (status != OK) { // Cannot currently test this, i.e. it shouldn't happen (and // currently there is no example where it does happen) gp_Free(&theGraph); ErrorQuit("Digraphs: boyers_planarity_check (C): internal error, " "can't add edge from %d to %d", (Int) v, (Int) u); return 0L; } } } } status = gp_Embed(theGraph, flags); if (status == NOTOK) { // Cannot currently test this, i.e. it shouldn't happen (and // currently there is no example where it does happen) gp_Free(&theGraph); ErrorQuit("Digraphs: boyers_planarity_check (C): status is not ok", 0L, 0L); } Obj res; if (krtwsk) { // Kuratowski subgraph isolator gp_SortVertices(theGraph); Obj subgraph = NEW_PLIST_IMM(T_PLIST, theGraph->N); SET_LEN_PLIST(subgraph, theGraph->N); for (int i = 1; i <= theGraph->N; ++i) { int nr = 0; Obj list = NEW_PLIST_IMM(T_PLIST, 0); int j = theGraph->V[i].link[1]; while (j) { if (CALL_3ARGS(IsDigraphEdge, digraph, INTOBJ_INT((Int) i), INTOBJ_INT((Int) theGraph->E[j].neighbor)) == True) { AssPlist(list, ++nr, INTOBJ_INT(theGraph->E[j].neighbor)); } j = theGraph->E[j].link[1]; } if (nr == 0) { RetypeBag(list, T_PLIST_EMPTY); } SET_ELM_PLIST(subgraph, i, list); CHANGED_BAG(subgraph); } res = NEW_PLIST_IMM(T_PLIST, 2); SET_LEN_PLIST(res, 2); SET_ELM_PLIST(res, 1, (status == NONEMBEDDABLE ? False : True)); SET_ELM_PLIST(res, 2, subgraph); CHANGED_BAG(res); } else if (status == NONEMBEDDABLE) { res = False; } else { res = True; } gp_Free(&theGraph); return res; }