//read all cluster tree information bool GmlParser::clusterRead(GmlObject* rootCluster, ClusterGraph& CG) { //the root cluster is only allowed to hold child clusters and //nodes in a list if (rootCluster->m_valueType != gmlListBegin) return false; // read all clusters and nodes GmlObject *rootClusterSon = rootCluster->m_pFirstSon; for(; rootClusterSon; rootClusterSon = rootClusterSon->m_pBrother) { switch(id(rootClusterSon)) { case clusterPredefKey: { //we could delete this, but we aviod the call if (rootClusterSon->m_valueType != gmlListBegin) return false; // set attributes to default values //we currently do not set any values cluster c = CG.newCluster(CG.rootCluster()); //recursively read cluster recursiveClusterRead(rootClusterSon, CG, c); } //case cluster break; case vertexPredefKey: //direct root vertices { if (rootClusterSon->m_valueType != gmlStringValue) return false; String vIDString = rootClusterSon->m_stringValue; //we only allow a vertex id as string identification if ((vIDString[0] != 'v') && (!isdigit(vIDString[0])))return false; //do not allow labels //if old style entry "v"i if (!isdigit(vIDString[0])) //should check prefix? vIDString[0] = '0'; //leading zero to allow conversion int vID = atoi(vIDString.cstr()); OGDF_ASSERT(m_mapToNode[vID] != 0) //we assume that no node is already assigned ! Changed: //all new nodes are assigned to root //CG.reassignNode(mapToNode[vID], CG.rootCluster()); //it seems that this may be unnessecary, TODO check CG.reassignNode(m_mapToNode[vID], CG.rootCluster()); //char* vIDChar = new char[vIDString.length()+1]; //for (int ind = 1; ind < vIDString.length(); ind++) // vIDChar }//case vertex }//switch }//for all rootcluster sons return true; }//clusterread
ClusterGraphCopy::ClusterGraphCopy(const ExtendedNestingGraph &H, const ClusterGraph &CG) : ClusterGraph(H), m_pCG(&CG), m_pH(&H), m_copy(CG,0) { m_original.init(*this,0); m_copy [CG.rootCluster()] = rootCluster(); m_original[rootCluster()] = CG.rootCluster(); createClusterTree(CG.rootCluster()); }
// write cluster graph structure with clusters static void write_ogml_graph(const ClusterGraph &C, ostream &os) { GraphIO::indent(os,2) << "<structure>\n"; write_ogml_graph(C.rootCluster(), 0, os); write_ogml_graph_edges(C.constGraph(), os); GraphIO::indent(os,2) << "</structure>\n"; }
//recursively read cluster subtree information bool GmlParser::recursiveClusterRead(GmlObject* clusterObject, ClusterGraph& CG, cluster c) { //for direct root cluster sons, this is checked twice... if (clusterObject->m_valueType != gmlListBegin) return false; GmlObject *clusterSon = clusterObject->m_pFirstSon; for(; clusterSon; clusterSon = clusterSon->m_pBrother) { //we dont read the attributes, therefore look only for //id and sons switch(id(clusterSon)) { case clusterPredefKey: { if (clusterSon->m_valueType != gmlListBegin) return false; cluster cson = CG.newCluster(c); //recursively read child cluster recursiveClusterRead(clusterSon, CG, cson); } break; case vertexPredefKey: //direct cluster vertex entries { if (clusterSon->m_valueType != gmlStringValue) return false; string vIDString = clusterSon->m_stringValue; //if old style entry "v"i if ((vIDString[0] != 'v') && (!isdigit((int)vIDString[0])))return false; //do not allow labels //if old style entry "v"i if (!isdigit((int)vIDString[0])) //should check prefix? vIDString[0] = '0'; //leading zero to allow conversion int vID = stoi(vIDString); OGDF_ASSERT(m_mapToNode[vID] != 0) //we assume that no node is already assigned //CG.reassignNode(mapToNode[vID], c); //changed: all nodes are already assigned to root CG.reassignNode(m_mapToNode[vID], c); //char* vIDChar = new char[vIDString.length()+1]; //for (int ind = 1; ind < vIDString.length(); ind++) // vIDChar }//case vertex }//switch }//for clustersons return true; }//recursiveclusterread
void ClusterGraphCopy::init(const ExtendedNestingGraph &H, const ClusterGraph &CG) { ClusterGraph::init(H); m_pCG = &CG; m_pH = &H; m_copy .init(CG,0); m_original.init(*this,0); m_copy [CG.rootCluster()] = rootCluster(); m_original[rootCluster()] = CG.rootCluster(); createClusterTree(CG.rootCluster()); }
//to be called AFTER calling read(G, AG) bool GmlParser::readAttributedCluster( Graph &G, ClusterGraph& CG, ClusterGraphAttributes& ACG) { OGDF_ASSERT(&CG.constGraph() == &G) //now we need the cluster object GmlObject *rootObject = m_objectTree; for(; rootObject; rootObject = rootObject->m_pBrother) if (id(rootObject) == rootClusterPredefKey) break; if(rootObject == nullptr) return true; if (id(rootObject) != rootClusterPredefKey) { setError("missing rootcluster key"); return false; } if (rootObject->m_valueType != gmlListBegin) return false; attributedClusterRead(rootObject, CG, ACG); return true; }//readAttributedCluster
bool GraphIO::writeDOT(const ClusterGraph &C, std::ostream &out) { const Graph &G = C.constGraph(); int id = 1; // Assign a list of edges for each cluster. Perhaps usage of std::vector // here needs reconsideration - vector is fast but usage of STL iterators // is ugly without C++11 for-each loop. ClusterArray< std::vector<edge> > edgeMap(C); for(edge e : G.edges) { const node s = e->source(), t = e->target(); edgeMap[C.commonCluster(s, t)].push_back(e); } return dot::writeCluster(out, 0, edgeMap, C, nullptr, C.rootCluster(), id); }
// Copy Function void ClusterGraph::shallowCopy(const ClusterGraph &C) { const Graph &G = C; m_pGraph = &G; m_nClusters = 0; //m_clusterDepth.init(*this, 0); initGraph(G); m_updateDepth = C.m_updateDepth; m_depthUpToDate = C.m_depthUpToDate; // Construct cluster tree ClusterArray<cluster> originalClusterTable(C); cluster c = 0; forall_clusters(c,C) { if (c == C.m_rootCluster) { originalClusterTable[c] = m_rootCluster; //does not really need to be assigned HERE in for m_rootCluster->depth() = 1; OGDF_ASSERT(C.rootCluster()->depth() == 1) continue; } originalClusterTable[c] = newCluster(); originalClusterTable[c]->depth() = c->depth(); }
bool CconnectClusterPlanar::preProcess(ClusterGraph &C,Graph &G) { if (!isCConnected(C)) { m_errorCode = nonCConnected; return false; } if (!isPlanar(C)) { m_errorCode = nonPlanar; return false; } cluster c; SListPure<node> selfLoops; makeLoopFree(G,selfLoops); c = C.rootCluster(); bool cPlanar = planarityTest(C,c,G); return cPlanar; }
bool CconnectClusterPlanar::preProcess(ClusterGraph &C,Graph &G) { if (!isCConnected(C)) { ogdf::sprintf(errorCode,124,"Graph is not C-connected \n"); m_errorCode = nonCConnected; return false; } PlanarModule Pm; if (!Pm.planarityTest(C)) { ogdf::sprintf(errorCode,124,"Graph is not planar\n"); m_errorCode = nonPlanar; return false; } cluster c; SListPure<node> selfLoops; makeLoopFree(G,selfLoops); c = C.rootCluster(); bool cPlanar = planarityTest(C,c,G); return cPlanar; }
bool GraphIO::writeGEXF(const ClusterGraph &C, std::ostream &out) { gexf::writeHeader(out); gexf::writeCluster(out, 1, C, nullptr, C.rootCluster()); gexf::writeFooter(out); return true; }
ClusterGraph::ClusterGraph(const ClusterGraph &C) : GraphObserver(&(C.getGraph())), m_clusterIdCount(0),m_postOrderStart(0), m_rootCluster(0), m_nClusters(0), m_lcaNumber(0), m_lcaSearch(0), m_vAncestor(0), m_wAncestor(0), m_allowEmptyClusters(1), m_updateDepth(false), m_depthUpToDate(false) { shallowCopy(C); m_clusterArrayTableSize = C.m_clusterArrayTableSize; }
static void writeCluster( std::ostream &out, int depth, const ClusterArray < std::vector<edge> > &edgeMap, const ClusterGraph &C, const ClusterGraphAttributes *CA, const cluster &c, int &clusterId) { if(C.rootCluster() == c) { writeHeader(out, depth++, CA); } else { GraphIO::indent(out, depth++) << "subgraph cluster" << clusterId << " {\n"; } clusterId++; bool whitespace; // True if a whitespace should printed (readability). whitespace = false; if(CA) { writeAttributes(out, depth, *CA, c); whitespace = true; } if(whitespace) { out << "\n"; } // Recursively export all subclusters. whitespace = false; for(ListConstIterator<cluster> cit = c->cBegin(); cit.valid(); ++cit) { writeCluster(out, depth, edgeMap, C, CA, *cit, clusterId); whitespace = true; } if(whitespace) { out << "\n"; } // Then, print all nodes whithout an adjacent edge. whitespace = false; for(ListConstIterator<node> nit = c->nBegin(); nit.valid(); ++nit) { whitespace |= writeNode(out, depth, CA, *nit); } if(whitespace) { out << "\n"; } // Finally, we print all edges for this cluster (ugly version for now). const std::vector<edge> &edges = edgeMap[c]; whitespace = false; for(size_t i = 0; i < edges.size(); i++) { whitespace |= writeEdge(out, depth, CA, edges[i]); } GraphIO::indent(out, --depth) << "}\n"; }
bool Parser::readCluster( Graph &G, ClusterGraph &C, ClusterGraphAttributes *CA, cluster rootCluster, const XmlTagObject &rootTag) { List<XmlTagObject *> nodeTags; rootTag.findSonXmlTagObjectByName("node", nodeTags); for(XmlTagObject *obj : nodeTags) { const XmlTagObject &nodeTag = *obj; XmlAttributeObject *idAttr; nodeTag.findXmlAttributeObjectByName("id", idAttr); if(!idAttr) { OGDF_ERROR("node is missing an attribute " << "(line " << nodeTag.getLine() << ")."); } // Node is a cluster iff it contains other nodes. XmlTagObject *nodesTag; nodeTag.findSonXmlTagObjectByName("nodes", nodesTag); if(nodesTag) { // Node tag found, therefore it is a cluster. const cluster c = C.newCluster(rootCluster); m_clusterId[idAttr->getValue()] = c; if(!readCluster(G, C, CA, c, *nodesTag)) { return false; } } else { // Node tag not found, therefore it is "normal" node. const node v = G.newNode(); C.reassignNode(v, rootCluster); m_nodeId[idAttr->getValue()] = v; if(CA) { readAttributes(*CA, v, nodeTag); } } } return true; }
bool GraphMLParser::readClusters( Graph &G, ClusterGraph &C, ClusterGraphAttributes *CA, const cluster &rootCluster, const pugi::xml_node rootTag) { for(pugi::xml_node nodeTag : rootTag.children("node")) { pugi::xml_attribute idAttr = nodeTag.attribute("id"); pugi::xml_node clusterTag = nodeTag.child("graph"); if (clusterTag == nullptr) { // Got normal node then, add it to the graph - id is required. if (!idAttr) { GraphIO::logger.lout() << "Node is missing id attribute." << endl; return false; } const node v = G.newNode(); m_nodeId[idAttr.value()] = v; C.reassignNode(v, rootCluster); // Read attributes when CA given and return false if error. if(CA && !readAttributes(*CA, v, nodeTag)) { return false; } } else { // Got a cluster node - read it recursively. const cluster c = C.newCluster(rootCluster); if (!readClusters(G, C, CA, c, clusterTag)) { return false; } // Read attributes when CA given and return false if error. if(CA && !readAttributes(*CA, c, nodeTag)) { return false; } } } return readEdges(G, CA, rootTag); }
bool GraphMLParser::read(Graph &G, ClusterGraph &C, ClusterGraphAttributes &CA) { if(m_error) { return false; } G.clear(); m_nodeId.clear(); return readClusters(G, C, &CA, C.rootCluster(), m_graphTag); }
bool GraphMLParser::read(Graph &G, ClusterGraph &C) { if(m_error) { return false; } G.clear(); m_nodeId.clear(); return readClusters(G, C, nullptr, C.rootCluster(), m_graphTag); }
//in ClusterGraph?? //is not yet recursive!!! node collapseCluster(ClusterGraph& CG, cluster c, Graph& G) { OGDF_ASSERT(c->cCount() == 0) ListIterator<node> its; SListPure<node> collaps; //we should check here if not empty node robinson = (*(c->nBegin())); for (its = c->nBegin(); its.valid(); its++) collaps.pushBack(*its); CG.collaps(collaps, G); if (c != CG.rootCluster()) CG.delCluster(c); return robinson; }
void CPlanarSubClusteredST::call(const ClusterGraph &CG, EdgeArray<bool>& inST) { initialize(CG); inST.fill(false); //representationsgraphs for every cluster, on clustergraph ClusterArray<Graph*> l_clusterRepGraph(CG, nullptr); computeRepresentationGraphs(CG, l_clusterRepGraph); //now we compute the spanning trees on the representation graphs //we should save the selection info on the original edge //are statically on the repgraphedges (we only have edge -> repedge //information) but ClusterArray< EdgeArray<bool> > l_inTree(CG); for(cluster c : CG.clusters) { l_inTree[c].init(*l_clusterRepGraph[c], false); //compute STs NodeArray<bool> visited(*l_clusterRepGraph[c], false); dfsBuildSpanningTree(l_clusterRepGraph[c]->firstNode(), l_inTree[c], visited); } OGDF_ASSERT(isConnected(CG.constGraph())); //compute the subclustered graph by constructing a spanning tree //using only the representation edges used in STs on the repgraphs NodeArray<bool> visited(CG, false); dfsBuildOriginalST(CG.constGraph().firstNode(), l_inTree, inST, visited); //unregister the edgearrays to avoid destructor failure after //representation graph deletion for(cluster c : CG.clusters) { l_inTree[c].init(); } deleteRepresentationGraphs(CG, l_clusterRepGraph); }
static void writeCluster( std::ostream &out, int depth, const ClusterGraph &C, const ClusterGraphAttributes *CA, cluster c) { if(C.rootCluster() != c) { GraphIO::indent(out, depth) << "<node " << "id=\"cluster" << c->index() << "\"" << ">\n"; } else { const std::string dir = (CA && !CA->directed()) ? "undirected" : "directed"; GraphIO::indent(out, depth) << "<graph " << "mode=\"static\"" << "defaultedgetype=\"" << dir << "\"" << ">\n"; if(CA) { defineAttributes(out, depth + 1, *CA); } } GraphIO::indent(out, depth + 1) << "<nodes>\n"; for(ListConstIterator<cluster> cit = c->cBegin(); cit.valid(); ++cit) { writeCluster(out, depth + 2, C, CA, *cit); } for(ListConstIterator<node> nit = c->nBegin(); nit.valid(); ++nit) { writeNode(out, depth + 2, CA, *nit); } GraphIO::indent(out, depth + 1) << "</nodes>\n"; if(C.rootCluster() != c) { GraphIO::indent(out, depth) << "</node>\n"; } else { writeEdges(out, C.constGraph(), CA); GraphIO::indent(out, depth) << "</graph>\n"; } }
void CPlanarSubClusteredST::initialize(const ClusterGraph& CG) { //initialize "call-global" info arrays m_allocCluster.init(CG, nullptr); //edge status #if 0 m_edgeStatus.init(CG.getGraph(), 0); #endif //edge to rep edge m_repEdge.init(CG, nullptr); //nodes and clusters to rep nodes m_cRepNode.init(CG, nullptr); m_vRepNode.init(CG, nullptr); }
// true <=> C is C-connected bool isCConnected(const ClusterGraph &C) { if(C.getGraph().empty()) return true; Graph G; ClusterGraph Cp(C,G); cluster root = Cp.rootCluster(); SListPure<node> compNodes; NodeArray<bool> mark(G,false); return cConnectTest(Cp,root,mark,G); }
ClusterGraph::ClusterGraph(const ClusterGraph &C) : GraphObserver(&(C.constGraph())), m_lcaSearch(0), m_vAncestor(0), m_wAncestor(0) { m_clusterIdCount = 0; m_postOrderStart = 0; m_rootCluster = 0; m_allowEmptyClusters = true; m_updateDepth = false; m_depthUpToDate = false; m_nClusters = 0; m_lcaNumber = 0; m_clusterArrayTableSize = C.m_clusterArrayTableSize; shallowCopy(C); }
// Copy Function void ClusterGraph::shallowCopy(const ClusterGraph &C) { const Graph &G = C; m_pGraph = &G; initGraph(G); m_updateDepth = C.m_updateDepth; m_depthUpToDate = C.m_depthUpToDate; // Construct cluster tree ClusterArray<cluster> originalClusterTable(C); for(cluster c : C.clusters) { if (c == C.m_rootCluster) { originalClusterTable[c] = m_rootCluster; //does not really need to be assigned HERE in for m_rootCluster->m_depth = 1; continue; } originalClusterTable[c] = newCluster(); originalClusterTable[c]->m_depth = c->depth(); } for(cluster c : C.clusters) { if (c == C.m_rootCluster) continue; originalClusterTable[c]->m_parent = originalClusterTable[c->m_parent]; originalClusterTable[c->m_parent]->children.pushBack(originalClusterTable[c]); originalClusterTable[c]->m_it = originalClusterTable[c->m_parent]->getChildren().rbegin(); } for(node v : G.nodes) reassignNode(v,originalClusterTable[C.clusterOf(v)]); copyLCA(C); }
//the clustergraph has to be initialized on G!!, //no clusters other then root cluster may exist, which holds all nodes bool GmlParser::readCluster(Graph &G, ClusterGraph& CG) { OGDF_ASSERT(&CG.constGraph() == &G) //now we need the cluster object GmlObject *rootObject = m_objectTree; for(; rootObject; rootObject = rootObject->m_pBrother) if (id(rootObject) == rootClusterPredefKey) break; //we have to check if the file does really contain clusters //otherwise, rootcluster will suffice if (rootObject == nullptr) return true; if (id(rootObject) != rootClusterPredefKey) { setError("missing rootcluster key"); return false; } if (rootObject->m_valueType != gmlListBegin) return false; clusterRead(rootObject, CG); return true; }//read clustergraph
void CPlanarSubClusteredST::call(const ClusterGraph& CG, EdgeArray<bool>& inST, EdgeArray<double>& weight) { initialize(CG); //representationsgraphs for every cluster, on clustergraph ClusterArray<Graph*> l_clusterRepGraph(CG, nullptr); computeRepresentationGraphs(CG, l_clusterRepGraph); //Now we compute the spanning trees on the representation graphs //are statically on the repgraphedges (we only have edge -> repedge //information) ClusterArray< EdgeArray<bool> > l_inTree(CG); //Weight of the representation edges ClusterArray< EdgeArray<double> > l_repWeight(CG); //Copy the weight for(cluster c : CG.clusters) { l_repWeight[c].init(*l_clusterRepGraph[c], 0.0); } for(edge e : CG.constGraph().edges) { l_repWeight[m_allocCluster[e]][m_repEdge[e]] = weight[e]; } for(cluster c : CG.clusters) { l_inTree[c].init(*l_clusterRepGraph[c], false); //compute STs computeMinST(*l_clusterRepGraph[c], l_repWeight[c], l_inTree[c]); } OGDF_ASSERT(isConnected(CG.constGraph())); //Compute the subclustered graph for(edge e : CG.constGraph().edges) { if (l_inTree[m_allocCluster[e]][m_repEdge[e]]) inST[e] = true; else inST[e] = false; } #ifdef OGDF_DEBUG GraphCopy cg(CG.constGraph()); for(edge e : CG.constGraph().edges) { if (!inST[e]) cg.delEdge(cg.copy(e)); } OGDF_ASSERT(isConnected(cg)); OGDF_ASSERT(cg.numberOfEdges() == cg.numberOfNodes()-1); #endif //unregister the edgearrays to avoid destructor failure after //representation graph deletion for(cluster c : CG.clusters) { l_inTree[c].init(); l_repWeight[c].init(); } deleteRepresentationGraphs(CG, l_clusterRepGraph); }
MaxCPlanarMaster::MaxCPlanarMaster( const ClusterGraph &C, int heuristicLevel, int heuristicRuns, double heuristicOEdgeBound, int heuristicNPermLists, int kuratowskiIterations, int subdivisions, int kSupportGraphs, double kHigh, double kLow, bool perturbation, double branchingGap, const char *time, bool dopricing, bool checkCPlanar, int numAddVariables, double strongConstraintViolation, double strongVariableViolation) : Master("MaxCPlanar", true, dopricing, OptSense::Max), m_numAddVariables(numAddVariables), m_strongConstraintViolation(strongConstraintViolation), m_strongVariableViolation(strongVariableViolation), m_fastHeuristicRuns(25), m_cutConnPool(nullptr), m_cutKuraPool(nullptr), m_useDefaultCutPool(true), m_checkCPlanar(checkCPlanar), m_porta(false) { // Reference to the given ClusterGraph and the underlying Graph. m_C = &C; m_G = &(C.constGraph()); // Create a copy of the graph as we need to modify it m_solutionGraph = new GraphCopy(*m_G); // Define the maximum number of variables needed. // The actual number needed may be much smaller, so there // is room for improvement... //ToDo: Just count how many vars are added //Max number of edges //KK: Check this change, added div 2 int nComplete = (m_G->numberOfNodes()*(m_G->numberOfNodes()-1)) / 2; m_nMaxVars = nComplete; //to use less variables in case we have only the root cluster, //we temporarily set m_nMaxVars to the number of edges if ( (m_C->numberOfClusters() == 1) && (isConnected(*m_G)) ) m_nMaxVars = m_G->numberOfEdges(); // Computing the main objective function coefficient for the connection edges. //int nConnectionEdges = nComplete - m_G->numberOfEdges(); m_epsilon = (double)(0.2/(2*(m_G->numberOfNodes()))); // Setting parameters m_nKuratowskiIterations = kuratowskiIterations; m_nSubdivisions = subdivisions; m_nKuratowskiSupportGraphs = kSupportGraphs; m_heuristicLevel = heuristicLevel; m_nHeuristicRuns = heuristicRuns; m_usePerturbation = perturbation; m_kuratowskiBoundHigh = kHigh; m_kuratowskiBoundLow = kLow; m_branchingGap = branchingGap; m_maxCpuTime = new string(time); m_heuristicFractionalBound = heuristicOEdgeBound; m_nHeuristicPermutationLists = heuristicNPermLists; m_mpHeuristic = true; // Further settings m_nCConsAdded = 0; m_nKConsAdded = 0; m_solvesLP = 0; m_varsInit = 0; m_varsAdded = 0; m_varsPotential = 0; m_varsMax = 0; m_varsCut = 0; m_varsKura = 0; m_varsPrice = 0; m_varsBranch = 0; m_activeRepairs = 0; m_repairStat.init(100); }
void CconnectClusterPlanar::constructWheelGraph(ClusterGraph &C, Graph &G, cluster &parent, PlanarPQTree* T, EdgeArray<node> &outgoingTable) { const PQNode<edge,IndInfo*,bool>* root = T->root(); const PQNode<edge,IndInfo*,bool>* checkNode = nullptr; Queue<const PQNode<edge,IndInfo*,bool>*> treeNodes; treeNodes.append(root); node correspond = G.newNode(); // Corresponds to the root node. // root node is either a leaf or a P-node C.reassignNode(correspond,parent); Queue<node> graphNodes; graphNodes.append(correspond); node hub; node next = nullptr; node pre; node newNode; // corresponds to anchor of a hub or a cut node while (!treeNodes.empty()) { checkNode = treeNodes.pop(); correspond = graphNodes.pop(); PQNode<edge,IndInfo*,bool>* firstSon = nullptr; PQNode<edge,IndInfo*,bool>* nextSon = nullptr; PQNode<edge,IndInfo*,bool>* oldSib = nullptr; PQNode<edge,IndInfo*,bool>* holdSib = nullptr; if (checkNode->type() == PQNodeRoot::PNode) { // correspond is a cut node OGDF_ASSERT(checkNode->referenceChild()) firstSon = checkNode->referenceChild(); if (firstSon->type() != PQNodeRoot::leaf) { treeNodes.append(firstSon); newNode = G.newNode(); C.reassignNode(newNode,parent); graphNodes.append(newNode); G.newEdge(correspond,newNode); } else { // insert Edge to the outside PQLeaf<edge,IndInfo*,bool>* leaf = (PQLeaf<edge,IndInfo*,bool>*) firstSon; edge f = leaf->getKey()->m_userStructKey; //node x = outgoingTable[f]; G.newEdge(correspond,outgoingTable[f]); delete leaf->getKey(); } nextSon = firstSon->getNextSib(oldSib); oldSib = firstSon; pre = next; while (nextSon && nextSon != firstSon) { if (nextSon->type() != PQNodeRoot::leaf) { treeNodes.append(nextSon); newNode = G.newNode(); // new node corresponding to anchor // or cutnode C.reassignNode(newNode,parent); graphNodes.append(newNode); G.newEdge(correspond,newNode); } else { // insert Edge to the outside PQLeaf<edge,IndInfo*,bool>* leaf = (PQLeaf<edge,IndInfo*,bool>*) nextSon; edge f = leaf->getKey()->m_userStructKey; //node x = outgoingTable[f]; G.newEdge(correspond,outgoingTable[f]); delete leaf->getKey(); } holdSib = nextSon->getNextSib(oldSib); oldSib = nextSon; nextSon = holdSib; } } else if (checkNode->type() == PQNodeRoot::QNode) { // correspond is the anchor of a hub OGDF_ASSERT(checkNode->getEndmost(PQNodeRoot::LEFT)) firstSon = checkNode->getEndmost(PQNodeRoot::LEFT); hub = G.newNode(); C.reassignNode(hub,parent); G.newEdge(hub,correspond); // link anchor and hub next = G.newNode(); // for first son C.reassignNode(next,parent); G.newEdge(hub,next); G.newEdge(correspond,next); if (firstSon->type() != PQNodeRoot::leaf) { treeNodes.append(firstSon); newNode = G.newNode(); C.reassignNode(newNode,parent); graphNodes.append(newNode); G.newEdge(next,newNode); } else { // insert Edge to the outside PQLeaf<edge,IndInfo*,bool>* leaf = (PQLeaf<edge,IndInfo*,bool>*) firstSon; edge f = leaf->getKey()->m_userStructKey; //node x = outgoingTable[f]; G.newEdge(next,outgoingTable[f]); delete leaf->getKey(); } nextSon = firstSon->getNextSib(oldSib); oldSib = firstSon; pre = next; while (nextSon) { next = G.newNode(); C.reassignNode(next,parent); G.newEdge(hub,next); G.newEdge(pre,next); if (nextSon->type() != PQNodeRoot::leaf) { treeNodes.append(nextSon); newNode = G.newNode(); // new node corresponding to anchor // or cutnode C.reassignNode(newNode,parent); graphNodes.append(newNode); G.newEdge(next,newNode); } else { // insert Edge to the outside PQLeaf<edge,IndInfo*,bool>* leaf = (PQLeaf<edge,IndInfo*,bool>*) nextSon; edge f = leaf->getKey()->m_userStructKey; G.newEdge(next,outgoingTable[f]); delete leaf->getKey(); } holdSib = nextSon->getNextSib(oldSib); oldSib = nextSon; nextSon = holdSib; pre = next; } G.newEdge(next,correspond); } } OGDF_ASSERT(C.consistencyCheck()); }
void CPlanarSubClusteredGraph::call(const ClusterGraph &CGO, EdgeArray<bool>& inSub, //original edges in subgraph? List<edge>& leftOver, //original edges not in subgraph EdgeArray<double>& edgeWeight) //prefer lightweight edges { leftOver.clear(); //we compute a c-planar subclustered graph by calling //CPlanarSubClusteredST and then perform reinsertion on //a copy of the computed subclustered graph //initialize "call-global" info arrays //edge status const Graph& origG = CGO.constGraph(); m_edgeStatus.init(origG, 0); CPlanarSubClusteredST CPST; if (edgeWeight.valid()) CPST.call(CGO, inSub, edgeWeight); else CPST.call(CGO, inSub); //now construct the copy //we should create a clusterGraph copy function that //builds a clustergraph upon a subgraph of the //original graph, preliminarily use fullcopy and delete edges ClusterArray<cluster> clusterCopy(CGO); NodeArray<node> nodeCopy(origG); EdgeArray<edge> edgeCopy(origG); Graph testG; ClusterGraph CG(CGO, testG, clusterCopy, nodeCopy, edgeCopy); CconnectClusterPlanar CCCP; //------------------------------------- //perform reinsertion of leftover edges //fill list of uninserted edges EdgeArray<bool> visited(origG,false); //delete the non-ST edges edge e; forall_edges(e, origG) { if (!inSub[e]) { leftOver.pushBack(e); //original edges testG.delEdge(edgeCopy[e]); }//if }//foralledges //todo: cope with preferred edges //simple reinsertion strategy: just iterate over list and test ListIterator<edge> itE = leftOver.begin(); while (itE.valid()) { //testG=CG.getGraph() edge newCopy = testG.newEdge(nodeCopy[(*itE)->source()], nodeCopy[(*itE)->target()]); edgeCopy[*itE] = newCopy; bool cplanar = CCCP.call(CG); if (!cplanar) { testG.delEdge(newCopy); itE++; }//if else { ListIterator<edge> itDel = itE; itE++; leftOver.del(itDel); } }//while /* ListConstIterator<edge> it; for(it = preferedEdges.begin(); it.valid(); ++it) { edge eG = *it; visited[eG] = true; edge eH = testG.newEdge(toTestG[eG->source()],toTestG[eG->target()]); if (preferedImplyPlanar == false && isPlanar(H) == false) { testG.delEdge(eH); delEdges.pushBack(eG); } } */ }//call
static bool writeCluster( std::ostream &out, int depth, const ClusterArray < std::vector<edge> > &edgeMap, const ClusterGraph &C, const ClusterGraphAttributes *CA, const cluster &c, int &clusterId) { std::ios_base::fmtflags currentFlags = out.flags(); out.flags(currentFlags | std::ios::fixed); bool result = out.good(); if(result) { if (C.rootCluster() == c) { writeHeader(out, depth++, CA); } else { GraphIO::indent(out, depth++) << "subgraph cluster" << clusterId << " {\n"; } clusterId++; bool whitespace; // True if a whitespace should printed (readability). whitespace = false; if (CA) { writeAttributes(out, depth, *CA, c); whitespace = true; } if (whitespace) { out << "\n"; } // Recursively export all subclusters. whitespace = false; for (cluster child : c->children) { writeCluster(out, depth, edgeMap, C, CA, child, clusterId); whitespace = true; } if (whitespace) { out << "\n"; } // Then, print all nodes whithout an adjacent edge. whitespace = false; for (node v : c->nodes) { whitespace |= writeNode(out, depth, CA, v); } if (whitespace) { out << "\n"; } // Finally, we print all edges for this cluster (ugly version for now). const std::vector<edge> &edges = edgeMap[c]; whitespace = false; for (auto &e : edges) { whitespace |= writeEdge(out, depth, CA, e); } GraphIO::indent(out, --depth) << "}\n"; } out.flags(currentFlags); return result; }