void findEulerTour(std::vector<T_Key>* sortedOutp) { UASSERT(sortedOutp->empty(), "Output graph must start empty"); if (debug() >= 6) dumpDotFilePrefixed("findEulerTour"); vl_unordered_set<unsigned /*edgeID*/> markedEdges; // Pick a start node Vertex* start_vertexp = castVertexp(verticesBeginp()); findEulerTourRecurse(&markedEdges, start_vertexp, sortedOutp); }
void V3Graph::userClearEdges() { // Clear user() in all of tree for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { edgep->user(0); edgep->userp(NULL); // Its a union, but might be different size than user() } } }
void V3Graph::clear() { // Empty it of all points, as if making a new object // Delete the old edges for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; /*BELOW*/) { V3GraphEdge* nextp = edgep->outNextp(); delete edgep; edgep = nextp; } vertexp->outUnlink(); } // Delete the old vertices for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; /*BELOW*/) { V3GraphVertex* nextp = vertexp->verticesNextp(); delete vertexp; vertexp = nextp; } verticesUnlink(); }
void V3Graph::userClearVertices() { // Clear user() in all of tree // We may use the userCnt trick in V3Ast later... (but gblCnt would be // in V3Graph instead of static - which has the complication of finding // the graph pointer given a vertex.) For now we don't call this often, and // the extra code on each read of user() would probably slow things // down more than help. for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { vertexp->user(0); vertexp->userp(NULL); // Its a union, but might be different size than user() } }
void dumpGraph(std::ostream& os, const string& nameComment) const { // UINFO(0) as controlled by caller os<<"At "<<nameComment<<", dumping graph. Keys:\n"; for (V3GraphVertex* vxp = verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { Vertex* tspvp = castVertexp(vxp); os<<" "<<tspvp->key()<<endl; for (V3GraphEdge* edgep = tspvp->outBeginp(); edgep; edgep = edgep->outNextp()) { Vertex* neighborp = castVertexp(edgep->top()); os<<" has edge "<<edgep->user()<<" to "<<neighborp->key()<<endl; } } }
std::vector<T_Key> getOddDegreeKeys() const { std::vector<T_Key> result; for (V3GraphVertex* vxp = verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { Vertex* tspvp = castVertexp(vxp); vluint32_t degree = 0; for (V3GraphEdge* edgep = vxp->outBeginp(); edgep; edgep = edgep->outNextp()) { degree++; } if (degree & 1) { result.push_back(tspvp->key()); } } return result; }
void V3Graph::dump(ostream& os) { // This generates a file used by graphviz, http://www.graphviz.org os<<" Graph:\n"; // Print vertices for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { os<<"\tNode: "<<vertexp->name(); if (vertexp->color()) os<<" color="<<vertexp->color(); os<<endl; // Print edges for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep=edgep->inNextp()) { dumpEdge (os, vertexp, edgep); } for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { dumpEdge (os, vertexp, edgep); } } }
void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) { // This generates a file used by graphviz, http://www.graphviz.org // "hardcoded" parameters: const auto_ptr<ofstream> logp (V3File::new_ofstream(filename)); if (logp->fail()) v3fatalSrc("Can't write "<<filename); // Header *logp<<"digraph v3graph {\n"; *logp<<"\tgraph\t[label=\""<<filename<<"\",\n"; *logp<<"\t\t labelloc=t, labeljust=l,\n"; *logp<<"\t\t //size="<<"\"7.5,10\","<<"\n"; *logp<<"\t\t rankdir="<<dotRankDir()<<"];\n"; // List of all possible subgraphs typedef multimap<string,V3GraphVertex*> SubgraphMmap; SubgraphMmap subgraphs; for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { string vertexSubgraph = (colorAsSubgraph && vertexp->color()) ? cvtToStr(vertexp->color()) : ""; subgraphs.insert(make_pair(vertexSubgraph, vertexp)); } // We use a map here, as we don't want to corrupt anything (userp) in the graph, // and we don't care if this is slow. map<V3GraphVertex*,int> numMap; // Print vertices int n=0; string subgr; for (SubgraphMmap::iterator it = subgraphs.begin(); it!=subgraphs.end(); ++it) { string vertexSubgraph = it->first; V3GraphVertex* vertexp = it->second; numMap[vertexp] = n; if (subgr != vertexSubgraph) { if (subgr!="") *logp<<"\t};\n"; subgr = vertexSubgraph; if (subgr!="") *logp<<"\tsubgraph cluster_"<<subgr<<" {\n"; } if (subgr!="") *logp<<"\t"; *logp<<"\tn"<<vertexp->dotName()<<(n++) <<"\t[fontsize=8 " <<"label=\""<<(vertexp->name()!="" ? vertexp->name() : "\\N"); if (vertexp->rank()) *logp<<" r"<<vertexp->rank(); if (vertexp->fanout()) *logp<<" f"<<vertexp->fanout(); if (vertexp->color()) *logp<<"\\n c"<<vertexp->color(); *logp<<"\""; *logp<<", color="<<vertexp->dotColor(); if (vertexp->dotStyle()!="") *logp<<", style="<<vertexp->dotStyle(); if (vertexp->dotShape()!="") *logp<<", shape="<<vertexp->dotShape(); *logp<<"];\n"; } if (subgr!="") *logp<<"\t};\n"; // Print edges for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { if (edgep->weight()) { int fromVnum = numMap[edgep->fromp()]; int toVnum = numMap[edgep->top()]; *logp<<"\tn"<<edgep->fromp()->dotName()<<fromVnum <<" -> n"<<edgep->top()->dotName()<<toVnum <<" [" //<<"fontsize=8 label=\""<<(edgep->name()!="" ? edgep->name() : "\\E")<<"\"" <<"fontsize=8 label=\""<<(edgep->dotLabel()!="" ? edgep->dotLabel() : "")<<"\"" <<" weight="<<edgep->weight() <<" color="<<edgep->dotColor(); if (edgep->dotStyle()!="") *logp<<" style="<<edgep->dotStyle(); //if (edgep->cutable()) { *logp<<",constraint=false"; } // to rank without following edges *logp<<"];\n"; } } } // Vertex::m_user end, now unused // Trailer *logp << "}\n"; logp->close(); cout << "dot -Tpdf -o ~/a.pdf "<<filename<<endl; }
void V3Graph::clearColors() { // Reset colors for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { vertexp->m_color = 0; } }
// From *this, populate *mstp with the minimum spanning tree. // *mstp must be initially empty. void makeMinSpanningTree(TspGraphTmpl* mstp) { UASSERT(mstp->empty(), "Output graph must start empty"); // Use Prim's algorithm to efficiently construct the MST. vl_unordered_set<Vertex*> visited_set; EdgeCmp cmp; typedef std::set<V3GraphEdge*, EdgeCmp&> PendingEdgeSet; // This is the set of pending edges from visited to unvisited // nodes. PendingEdgeSet pendingEdges(cmp); vluint32_t vertCount = 0; for (V3GraphVertex* vxp = verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { mstp->addVertex(castVertexp(vxp)->key()); vertCount++; } // Choose an arbitrary start vertex and visit it; // all incident edges from this vertex go into a pending edge set. Vertex* start_vertexp = castVertexp(verticesBeginp()); visited_set.insert(start_vertexp); for (V3GraphEdge* edgep = start_vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { pendingEdges.insert(edgep); } // Repeatedly find the least costly edge in the pending set. // If it connects to an unvisited node, visit that node and update // the pending edge set. If it connects to an already visited node, // discard it and repeat again. unsigned edges_made = 0; while (!pendingEdges.empty()) { typename PendingEdgeSet::iterator firstIt = pendingEdges.begin(); V3GraphEdge* bestEdgep = *firstIt; pendingEdges.erase(firstIt); // bestEdgep->fromp() should be already seen Vertex* from_vertexp = castVertexp(bestEdgep->fromp()); UASSERT(visited_set.find(from_vertexp) != visited_set.end(), "Can't find vertex"); // If the neighbor is not yet visited, visit it and add its edges // to the pending set. Vertex* neighborp = castVertexp(bestEdgep->top()); if (visited_set.find(neighborp) == visited_set.end()) { int bestCost = bestEdgep->weight(); UINFO(6, "bestCost = "<<bestCost <<" from "<<from_vertexp->key() <<" to "<<neighborp->key()<<endl); // Create the edge in our output MST graph mstp->addEdge(from_vertexp->key(), neighborp->key(), bestCost); edges_made++; // Mark this vertex as visited visited_set.insert(neighborp); // Update the pending edges with new edges for (V3GraphEdge* edgep = neighborp->outBeginp(); edgep; edgep = edgep->outNextp()) { pendingEdges.insert(edgep); } } else { UINFO(6, "Discarding edge to already-visited neighbor " <<neighborp->key()<<endl); } } UASSERT(edges_made + 1 == vertCount, "Algorithm failed"); UASSERT(visited_set.size() == vertCount, "Algorithm failed"); }