예제 #1
0
	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]);
		}
	}
예제 #2
0
//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;
}
예제 #3
0
// 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;

}