Пример #1
0
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;
}
Пример #2
0
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;
}
// Prepares the planarity test and the planar embedding
// Parallel edges:  do not need to be ignored, they can be handled
// by the planarity test.
// Selfloops: need to be ignored.
bool PlanarModule::preparation(Graph  &G,bool embed)
{

	if (G.numberOfEdges() < 9 && !embed)
		return true;
	else if (G.numberOfEdges() < 3 && embed)
		return true;


	node v;
	edge e;

	SListPure<node> selfLoops;
	makeLoopFree(G,selfLoops);

	prepareParallelEdges(G);

	int  isolated = 0;
	forall_nodes(v,G)
		if (v->degree() == 0)
			isolated++;

	if (((G.numberOfNodes()-isolated) > 2) &&
		((3*(G.numberOfNodes()-isolated) -6) < (G.numberOfEdges() - m_parallelCount)))
		return false;



	bool planar = true;


	NodeArray<node> tableNodes(G,0);
	EdgeArray<edge> tableEdges(G,0);
	NodeArray<bool> mark(G,0);

	EdgeArray<int> componentID(G);


	// Determine Biconnected Components
	int bcCount = biconnectedComponents(G,componentID);

	// Determine edges per biconnected component
	Array<SList<edge> > blockEdges(0,bcCount-1);
	forall_edges(e,G)
	{
		blockEdges[componentID[e]].pushFront(e);
	} 
Пример #4
0
void OptimalRanking::doCall(
	const Graph& G,
	NodeArray<int> &rank,
	EdgeArray<bool> &reversed,
	const EdgeArray<int> &length,
	const EdgeArray<int> &costOrig)
{
	MinCostFlowReinelt<int> mcf;

	// construct min-cost flow problem
	GraphCopy GC;
	GC.createEmpty(G);

	// compute connected component of G
	NodeArray<int> component(G);
	int numCC = connectedComponents(G,component);

	// intialize the array of lists of nodes contained in a CC
	Array<List<node> > nodesInCC(numCC);

	for(node v : G.nodes)
		nodesInCC[component[v]].pushBack(v);

	EdgeArray<edge> auxCopy(G);
	rank.init(G);

	for(int i = 0; i < numCC; ++i)
	{
		GC.initByNodes(nodesInCC[i], auxCopy);
		makeLoopFree(GC);

		for(edge e : GC.edges)
			if(reversed[GC.original(e)])
				GC.reverseEdge(e);

		// special cases:
		if(GC.numberOfNodes() == 1) {
			rank[GC.original(GC.firstNode())] = 0;
			continue;
		} else if(GC.numberOfEdges() == 1) {
			edge e = GC.original(GC.firstEdge());
			rank[e->source()] = 0;
			rank[e->target()] = length[e];
			continue;
		}

		EdgeArray<int> lowerBound(GC,0);
		EdgeArray<int> upperBound(GC,mcf.infinity());
		EdgeArray<int> cost(GC);
		NodeArray<int> supply(GC);

		for(edge e : GC.edges)
			cost[e] = -length[GC.original(e)];

		for(node v : GC.nodes) {
			int s = 0;
			edge e;
			forall_adj_edges(e,v) {
				if(v == e->source())
					s += costOrig[GC.original(e)];
				else
					s -= costOrig[GC.original(e)];
			}
			supply[v] = s;
		}

		OGDF_ASSERT(isAcyclic(GC) == true);

		// find min-cost flow
		EdgeArray<int> flow(GC);
		NodeArray<int> dual(GC);
#ifdef OGDF_DEBUG
		bool feasible =
#endif
			mcf.call(GC, lowerBound, upperBound, cost, supply, flow, dual);
		OGDF_ASSERT(feasible);

		for(node v : GC.nodes)
			rank[GC.original(v)] = dual[v];
	}
}
Пример #5
0
//---------------------------------------------------------
//actual call
//minDegree default 2, all other nodes are skipped
//only high values have an impact because we only
//work on triconnected components, skipping all low
//degree nodes (but we make the test graphcopy biconnected
//afterwards)
void CliqueFinder::doCall(int minDegree)
{
	//---------------------------------------------
	//initialize structures and check preconditions
	//---------------------------------------------
	m_copyCliqueNumber.init(*m_pCopy, -1);
	m_usedNode.init(*m_pCopy, false);
	makeParallelFreeUndirected(*m_pCopy); //it doesnt make sense to count loops
	makeLoopFree(*m_pCopy);               //or parallel edges

	m_numberOfCliques = 0;
	//We first indentify the biconnected components of
	//the graph to allow the use of the SPQR-tree data
	//Structure. Latter then separates the different
	//triconnected components on which we finally work

	//TODO: delete all copy nodes with degree < minDegree

	int nodeNum = m_pGraph->numberOfNodes();
	//TODO: change for non-cliques, where this is not necessary
	if (nodeNum < minDegree) return; //nothing to find for cliques

	//-------------------------------------------------------
	//Special cases:
	//Precondition for SPQR-trees: graph has at least 3 nodes
	//or 2 nodes and at least 3 edges
	//TODO: check this after makebiconnected

	//----------------------------
	//set values for trivial cases
	if (nodeNum < 3)
	{
		//only set numbers for the special case
		if (nodeNum == 2)
		{
			if (m_pGraph->numberOfEdges() >= 1)  //> 2)
			{
				node w = m_pCopy->firstNode();
				m_copyCliqueNumber[w] = 0;
				w = w->succ();
				m_copyCliqueNumber[w] = 0;
			}
			else
			{
				if (minDegree == 0)
				{
					node w = m_pCopy->firstNode();
					m_copyCliqueNumber[w] = 0;
					w = w->succ();
					m_copyCliqueNumber[w] = 1;
				}//if no mindegree

			}
		}//if two nodes
		else if ( (nodeNum == 1) && (minDegree <= 0))
				m_copyCliqueNumber[m_pCopy->firstNode()] = 0;

		return;
	}//graph too small

	OGDF_ASSERT(m_pCopy != 0)

	//save the original edges
	EdgeArray<bool> originalEdge(*m_pCopy, true);
	List<edge> added;


	//we make the copy biconnected, this keeps the triconnected
	//components


	//-------------------------------------------------------------
	//store the original node degrees:
	//afterwards we want to be able to sort the nodes corresponding
	//to their real degree, not the one with the additional
	//connectivity edges
	NodeArray<int> realDegree(*m_pCopy, -1);//no isolated nodes exist here
	//relative degree, number of high degree neighbours
	NodeArray<int> relDegree(*m_pCopy, 0);//no isolated nodes exist here
	for(node v : m_pCopy->nodes)
	{
		realDegree[v] = v->degree();
		if (v->degree() > 0)
		{
			adjEntry adRun = v->firstAdj();
			while (adRun)
			{
				adjEntry succ = adRun->succ();
				if (adRun->twinNode()->degree() >= minDegree)
					relDegree[v]++;
				adRun = succ;
			}//while
		}//if not isolated

	}

	makeBiconnected(*m_pCopy, added);

	//TODO: We can decrease node degrees by the number of adjacent
	//low degree nodes to sort them only by number of relevant connections
	//PARTIALLY DONE: relDegree

	//storing the component number, there are no isolated nodes now
	EdgeArray<int> component(*m_pCopy);

	StaticSPQRTree spqrTree(*m_pCopy);

	//Return if there are no R-nodes
	if (spqrTree.numberOfRNodes() == 0)
	{
		//TODO:set node numbers for cliques
		//that are not triconnected
		//each edge is a min. clique for mindegree 1
		//each triangle for mindegree 2?

		return;
	}//if

	//the degree of the original node
	//within the triconnected component
	NodeArray<int> ccDegree(*m_pCopy, 0);

	for(node v : spqrTree.tree().nodes)
	{
		//we search for dense subgraphs in R-Nodes
		//heuristics:
		//sort the nodes by their degree within the component
		//in descending order, then start cliques by initializing
		//them with the first node and checking the remaining,
		//starting new cliques with nodes that don't fit in the
		//existing cliques (stored in cliqueList)

		if (spqrTree.typeOf(v) == SPQRTree::RNode)
		{
			//retrieve the skeleton
			Skeleton &s = spqrTree.skeleton(v);
			Graph &skeletonG = s.getGraph();

			//list of cliques
			List< List<node>* > cliqueList;

			//we insert all nodes into a list to sort them
			List<node> sortList;

			//save the usable edges within the triconnected component
			EdgeArray<bool> usableEdge(*m_pCopy, false);

			//derive the degree of the original node
			//within the triconnected component
			for(node w : skeletonG.nodes)
			{
				node vOrig = s.original(w);

				edge eSkel;
				forall_adj_edges(eSkel, w)
				{
					edge goodEdge = s.realEdge(eSkel);
					bool isGoodEdge = goodEdge != nullptr;
					if (isGoodEdge) isGoodEdge = m_pCopy->original(goodEdge) != nullptr;
					//if (s.realEdge(eSkel))
					if (isGoodEdge)
					{
						ccDegree[vOrig]++;
						usableEdge[goodEdge] = true;
					}
				}//foralladjedges

				sortList.pushBack(vOrig);

			}

			//sort the nodes corresponding to their degree
			NodeComparer<int> ncomp(ccDegree, false);
			sortList.quicksort(ncomp);

			ListIterator<node> itNode = sortList.begin();

			while(itNode.valid())
			{

				//hier erst vergleichen, ob Knoten Grad > aktcliquengroesse,
				//dann ob mit clique verbunden
				//alternativ koennte man stattdessen fuer jeden gewaehlten
				//Knoten nur noch seine Nachbarn als Kandidaten zulassen
				//hier sollte man mal ein paar Strategien testen, z.B.
				//streng nach Listenordnung vorgehen oder eine "Breitensuche"
				//vom Startknoten aus..
				node vCand = *itNode;

				//node can appear in several 3connected components
				if (m_usedNode[vCand])
				{
					++itNode;
					continue;
				}//if already used

				//if there are only "small" degree nodes left, we stop
				//if (vCand->degree() < minDegree)
				if (ccDegree[vCand] < minDegree)
					break;

				//------------------------------------------------
				//successively check the node against the existing
				//clique candidates

				//run through the clique candidates to find a matching
				//node set
				bool setFound = false;
				ListIterator< List<node>* > itCand = cliqueList.begin();
				while (itCand.valid())
				{

					//in the case of cliques, the node needs min degree
					//greater or equal to current clique size
					//TODO: adapt to dense subgraphs
					bool isCand = false;
					if (m_density == 100)
						isCand = (vCand->degree() >= (*itCand)->size());
					else isCand = (vCand->degree() >= ceil(m_density*(*itCand)->size()/100.0));
					if (isCand)
					{
						//TODO: insert adjacency oracle here to speed
						//up the check?
						//TODO: check if change from clique to dense subgraph criterion
						//violates some preconditions for our search
						if (allAdjacent(vCand, (*itCand)))
						{
							OGDF_ASSERT(m_usedNode[*itNode] == false)
							(*itCand)->pushBack(*itNode);
							setFound = true;
							m_usedNode[(*itNode)] = true;

							//bubble sort the clique after insertion of the node
							//while size > predsize swap positions
							ListIterator< List<node>* > itSearch = itCand.pred();
							if (itSearch.valid())
							{
								while (itSearch.valid() &&
									( (*itCand)->size() > (*itSearch)->size()) )
								{
									--itSearch;
								}
								//If valid, move behind itSearch, else move to front
								if (!itSearch.valid())
									cliqueList.moveToFront(itCand);
								else cliqueList.moveToSucc(itCand, itSearch);
							}//if valid

							break;
						}//if node fits into node set
					}//if sufficient degree
					//hier kann man mit else breaken, wenn Liste immer sortiert ist

					++itCand;
				}//while clique candidates

				//create a new candidate if necessary
				if (!setFound)
				{
					List<node>* cliqueCandidate = OGDF_NEW List<node>();
					itCand = cliqueList.pushBack(cliqueCandidate);
					OGDF_ASSERT(m_usedNode[*itNode] == false)
					cliqueCandidate->pushBack(*itNode);
					m_usedNode[(*itNode)] = true;

				}//if no candidate yet

				++itNode;
			}//while valid

			//TODO: cliquelist vielleicht durch einen member ersetzen
			//und nicht das delete vergessen!
#ifdef OGDF_DEBUG
			//int numC1 = cliqueList.size();

			//int nodeNum = 0;
			//for (List<node> *pL : cliqueList)
			//{
			//	if ( pL->size() > minDegree )
			//		nodeNum = nodeNum + pL->size();
			//}
			checkCliques(cliqueList, false);
			//double realTime;
			//ogdf::usedTime(realTime);
#endif
			postProcessCliques(cliqueList, usableEdge);
#ifdef OGDF_DEBUG
			//realTime = ogdf::usedTime(realTime);

			//int nodeNum2 = 0;
			//for (List<node> *pL : cliqueList)
			//{
			//	if ( pL->size() > minDegree )
			//		nodeNum2 = nodeNum2 + pL->size();
			//}
			//if (nodeNum2 > nodeNum)
			//{
			//	cout<<"\nAnzahl Cliquen vor PP: "<<numC1<<"\n";
			//	cout<<"Anzahl Cliquen nach PP: "<<cliqueList.size()<<"\n";
			//	cout<<"Anzahl Knoten in grossen Cliquen: "<<nodeNum<<"\n";
			//	cout<<"Anzahl Knoten danach in grossen Cliquen: "<<nodeNum2<<"\n\n";
			//}
			//cout << "Used postprocessing time: " << realTime << "\n" << flush;
			checkCliques(cliqueList, false);
#endif

			//now we run through the list until the remaining node sets
			//are to small to be of interest
			for(List<node> *pCand : cliqueList)
			{
				if ( pCand->size() <= minDegree ) break;

				for(node u : *pCand)
				{
					OGDF_ASSERT(m_copyCliqueNumber[u] == -1)
					m_copyCliqueNumber[u] = m_numberOfCliques;
				}//for clique nodes
				m_numberOfCliques++;
			}
			//TODO: only set numbers if return value is not a list
			//of clique node lists
			setResults(cliqueList);

			//free the allocated memory
			for(List<node> *pCl : cliqueList)
			{
				delete pCl;
			}

		}//if