forall_clusters(c,CG) { if(c != CG.rootCluster()) { cluster u = c->parent(); newEdge(m_topNode[u], m_topNode[c]); newEdge(m_bottomNode[c], m_bottomNode[u]); newEdge(m_topNode[c], m_bottomNode[c]); } }
//compute bag affiliation for all vertices //store result in m_bagindex void ClusterAnalysis::computeBags() { const Graph &G = m_C->constGraph(); // Storage structure for results m_bagindex.init(G); // We use Union-Find for chunks and bags DisjointSets<> uf; NodeArray<int> setid(G); // Index mapping for union-find #if 0 node* nn = new node[G.numberOfNodes()]; // dito #endif // Every cluster gets its index ClusterArray<int> cind(*m_C); // We store the lists of cluster vertices List<node>* clists = new List<node>[m_C->numberOfClusters()]; int i = 0; // Store index and detect the current leaf clusters List<cluster> ccleafs; ClusterArray<int> unprocessedChildren(*m_C); //processing below: compute bags for(cluster c : m_C->clusters) { cind[c] = i++; if (c->cCount() == 0) ccleafs.pushBack(c); unprocessedChildren[c] = c->cCount(); } // Now we run through all vertices, storing them in the parent lists, // at the same time, we initialize m_bagindex for(node v : G.nodes) { // setid is constant in the following setid[v] = uf.makeSet(); // Each vertex v gets its own ClusterArray that stores v's bag index per cluster. // See comment on use of ClusterArrays above m_bagindex[v] = new ClusterArray<int>(*m_C,DefaultIndex, m_C->maxClusterIndex()+1);//m_C->numberOfClusters()); cluster c = m_C->clusterOf(v); // Push vertices in parent list clists[cind[c]].pushBack(v); } // Now each clist contains the direct vertex descendants // We process the clusters bottom-up, compute the chunks // of the leafs first. At each level, for a cluster the // vertex lists of all children are concatenated // (could improve this by having an array of size(#leafs) // and concatenating only at child1), then the bags are // updated as follows: chunks may be linked by exactly // the edges with lca(c) ie the ones in m_lcaEdges[c], // and bags may be built by direct child clusters that join chunks. // While concatenating the vertex lists, we can check // for the vertices in each child if the uf number is the same // as the one of a first initial vertex, otherwise we join. // First, lowest level clusters are processed: All chunks are bags OGDF_ASSERT(!ccleafs.empty()); while (!ccleafs.empty()){ const cluster c = ccleafs.popFrontRet(); Skiplist<int*> cbags; //Stores bag indexes ocurring in c auto storeResult = [&] { for (node v : clists[cind[c]]) { int theid = uf.find(setid[v]); (*m_bagindex[v])[c] = theid; if (!cbags.isElement(&theid)) { cbags.add(new int(theid)); } // push into list of outer active vertices if (m_storeoalists && isOuterActive(v, c)) { (*m_oalists)[c].pushBack(v); } } (*m_bags)[c] = cbags.size(); // store number of bags of c }; if (m_storeoalists){ //no outeractive vertices detected so far (*m_oalists)[c].clear(); } //process leafs separately if (c->cCount() == 0) { //Todo could use lcaEdges list here too, see below for (node u : c->nodes) { for(adjEntry adj : u->adjEntries) { node w = adj->twinNode(); if (m_C->clusterOf(w) == c) { uf.link(uf.find(setid[u]),uf.find(setid[w])); } } } // Now all chunks in the leaf cluster are computed // update for parent is done in the else case storeResult(); } else { // ?We construct the vertex list by concatenating // ?the lists of the children to the current list. // We need the lists for storing the results efficiently. // (Should be slightly faster than to call clusterNodes each time) // Bags are either links of chunks by edges with lca==c // or links of chunk by child clusters. // Edge links for(edge e : (*m_lcaEdges)[c]) { uf.link(uf.find(setid[e->source()]),uf.find(setid[e->target()])); } // Cluster links for(cluster cc : c->children) { //Initial id per child cluster cc: Use value of first //vertex, each time we encounter a different value in cc, //we link the chunks //add (*itcc)'s vertices to c's list ListConstIterator<node> itvc = clists[cind[cc]].begin(); int inid; if (itvc.valid()) inid = uf.find(setid[*itvc]); while (itvc.valid()) { int theid = uf.find(setid[*itvc]); if (theid != inid) uf.link(inid,theid); clists[cind[c]].pushBack(*itvc); ++itvc; } } storeResult(); } // Now we update the status of the parent cluster and, // in case all its children are processed, add it to // the process queue. if (c != m_C->rootCluster()) { OGDF_ASSERT(unprocessedChildren[c->parent()] > 0); unprocessedChildren[c->parent()]--; if (unprocessedChildren[c->parent()] == 0) ccleafs.pushBack(c->parent()); } } // clean up delete[] clists; }
// Recursive call for testing c-planarity of the clustered graph // that is induced by cluster act bool CconnectClusterPlanar::planarityTest( ClusterGraph &C, cluster &act, Graph &G) { // Test children first ListConstIterator<cluster> it; for (it = act->cBegin(); it.valid();) { ListConstIterator<cluster> succ = it.succ(); cluster next = (*it); if (!planarityTest(C,next,G)) return false; it = succ; } // Get induced subgraph of cluster act and test it for planarity List<node> subGraphNodes; for (node s : act->nodes) subGraphNodes.pushBack(s); Graph subGraph; NodeArray<node> table; inducedSubGraph(G,subGraphNodes.begin(),subGraph,table); // Introduce super sink and add edges corresponding // to outgoing edges of the cluster node superSink = subGraph.newNode(); EdgeArray<node> outgoingTable(subGraph,nullptr); for (node w : act->nodes) { //adjEntry adj = w->firstAdj(); for(adjEntry adj : w->adjEntries) { edge e = adj->theEdge(); edge cor = nullptr; if (table[e->source()] == nullptr) // edge is connected to a node outside the cluster { cor = subGraph.newEdge(table[e->target()],superSink); outgoingTable[cor] = e->source(); } else if (table[e->target()] == nullptr) // dito { cor = subGraph.newEdge(table[e->source()],superSink); outgoingTable[cor] = e->target(); } // else edge connects two nodes of the cluster } } if (superSink->degree() == 0) // root cluster is not connected to outside clusters { subGraph.delNode(superSink); superSink = nullptr; } bool cPlanar = preparation(subGraph,act,superSink); if (cPlanar && act != C.rootCluster()) { // Remove induced subgraph and the cluster act. // Replace it by a wheel graph while (!subGraphNodes.empty()) { node w = subGraphNodes.popFrontRet(); // C.unassignNode(w); G.delNode(w); } cluster parent = act->parent(); if (superSink && m_clusterPQTree[act]) constructWheelGraph(C,G,parent,m_clusterPQTree[act],outgoingTable); C.delCluster(act); if (m_clusterPQTree[act] != nullptr) // if query necessary for clusters with just one child { m_clusterPQTree[act]->emptyAllPertinentNodes(); delete m_clusterPQTree[act]; } } else if (!cPlanar) { m_errorCode = nonCPlanar; }//if not cplanar return cPlanar; }