예제 #1
0
void SubgraphPlanarizer::CrossingStructure::init(PlanRep &PG, int weightedCrossingNumber)
{
	m_weightedCrossingNumber = weightedCrossingNumber;
	m_crossings.init(PG.original());
	
	m_numCrossings = 0;
	NodeArray<int> index(PG,-1);
	node v;
	forall_nodes(v,PG)
		if(PG.isDummy(v))
			index[v] = m_numCrossings++;

	edge ePG;
	forall_edges(ePG,PG)
	{
		if(PG.original(ePG->source()) != 0) {
			edge e = PG.original(ePG);
			ListConstIterator<edge> it = PG.chain(e).begin();
			for(++it; it.valid(); ++it) {
				//cout << index[(*it)->source()] << " ";
				m_crossings[e].pushBack(index[(*it)->source()]);
			}
		}
	}	
}
예제 #2
0
void SubgraphPlanarizer::CrossingStructure::restore(PlanRep &PG, int cc)
{
	//PG.initCC(cc);
	
	Array<node> id2Node(0,m_numCrossings-1,0);
	
	SListPure<edge> edges;
	PG.allEdges(edges);

	for(SListConstIterator<edge> itE = edges.begin(); itE.valid(); ++itE)
	{
		edge ePG = *itE;
		edge e = PG.original(ePG);
		
		SListConstIterator<int> it;
		for(it = m_crossings[e].begin(); it.valid(); ++it)
		{
			node x = id2Node[*it];
			edge ePGOld = ePG;
			ePG = PG.split(ePG);
			node y = ePG->source();
			
			if(x == 0) {
				id2Node[*it] = y;
			} else {
				PG.moveTarget(ePGOld, x);
				PG.moveSource(ePG, x);
				PG.delNode(y);
			}
		}
	}
}
//---------------------------------------------------------
// actual call (called by all variations of call)
//   crossing of generalizations is forbidden if forbidCrossingGens = true
//   edge costs are obeyed if costOrig != 0
//
Module::ReturnType FixedEmbeddingInserter::doCall(
	PlanRep &PG,
	const List<edge> &origEdges,
	bool forbidCrossingGens,
	const EdgeArray<int>  *costOrig,
	const EdgeArray<bool> *forbiddenEdgeOrig,
	const EdgeArray<unsigned int> *edgeSubGraph)
{
  
	double T;
	usedTime(T);
	
	ReturnType retValue = retFeasible;
	m_runsPostprocessing = 0;

	PG.embed(); 
	OGDF_ASSERT(PG.representsCombEmbedding() == true);

	if (origEdges.size() == 0)
		return retOptimal;  // nothing to do

#ifdef OGDF_DEBUG
	// Check if no edge in the list origEdges is forbidden
	if(forbiddenEdgeOrig != 0) {
		ListConstIterator<edge> itTemp;
		for(itTemp = origEdges.begin(); itTemp.valid(); ++itTemp)
			OGDF_ASSERT((*forbiddenEdgeOrig)[*itTemp] == false);
	}
#endif

	// initialization
	CombinatorialEmbedding E(PG);  // embedding of PG

	m_dual.clear();
	m_primalAdj.init(m_dual);
	m_nodeOf.init(E);

	// construct dual graph
	m_primalIsGen.init(m_dual,false);

	OGDF_ASSERT(forbidCrossingGens == false || forbiddenEdgeOrig == 0);

	if(forbidCrossingGens)
		constructDualForbidCrossingGens((const PlanRepUML&)PG,E);
	else
		constructDual(PG,E,forbiddenEdgeOrig);

#ifdef OGDF_DEBUG
	if(forbiddenEdgeOrig != 0) {
		edge e;
		forall_edges(e,m_dual) {
			OGDF_ASSERT((*forbiddenEdgeOrig)[PG.original(m_primalAdj[e]->theEdge())] == false);
		}
void AbacusOptimalCrossingMinimizer::KuratowskiConstraint::addAccordingCrossing(
		const Subproblem* S, const PlanRep& I, edge e, int eid, List<CrossingInfo*>& L) {
	const List<edge>& le = I.chain(e);
	
	OGDF_ASSERT( le.size() == 2 );
	OGDF_ASSERT( le.front()->target() == le.back()->source() );
	
	node n = le.front()->target();
	edge c, te;
	forall_adj_edges(te, n) {
		c = I.original(te);
		if(c != e) break;
	}
예제 #5
0
//---------------------------------------------------------
// actual call (called by all variations of call)
//   crossing of generalizations is forbidden if forbidCrossingGens = true
//   edge costs are obeyed if costOrig != 0
//
Module::ReturnType FixedEmbeddingInserter::doCall(
	PlanRep &PG,
	const List<edge> &origEdges,
	bool forbidCrossingGens,
	const EdgeArray<int>  *costOrig,
	const EdgeArray<bool> *forbiddenEdgeOrig,
	const EdgeArray<unsigned int> *edgeSubGraph)
{
  
	double T;
	usedTime(T);
	
	ReturnType retValue = retFeasible;
	m_runsPostprocessing = 0;

	PG.embed(); 
	OGDF_ASSERT(PG.representsCombEmbedding() == true);

	if (origEdges.size() == 0)
		return retOptimal;  // nothing to do

	// initialization
	CombinatorialEmbedding E(PG);  // embedding of PG

	m_dual.clear();
	m_primalAdj.init(m_dual);
	m_nodeOf.init(E);

	// construct dual graph
	m_primalIsGen.init(m_dual,false);

	OGDF_ASSERT(forbidCrossingGens == false || forbiddenEdgeOrig == 0);

	if(forbidCrossingGens)
		constructDualForbidCrossingGens((const PlanRepUML&)PG,E);
	else
		constructDual(PG,E,forbiddenEdgeOrig);

	// m_delFaces and m_newFaces are used by removeEdge()
	// if we can't allocate memory for them, we throw an exception
	if (removeReinsert() != rrNone) {
		m_delFaces = new FaceSetSimple(E);
		if (m_delFaces == 0)
			OGDF_THROW(InsufficientMemoryException);

		m_newFaces = new FaceSetPure(E);
		if (m_newFaces == 0) {
			delete m_delFaces;
			OGDF_THROW(InsufficientMemoryException);
		}

	// no postprocessing -> no removeEdge()
	} else {
		m_delFaces = 0;
		m_newFaces = 0;
	}

	SListPure<edge> currentOrigEdges;
	if(removeReinsert() == rrIncremental) {
		edge e;
		forall_edges(e,PG)
			currentOrigEdges.pushBack(PG.original(e));
	}

	// insertion of edges
	ListConstIterator<edge> it;
	for(it = origEdges.begin(); it.valid(); ++it)
	{
		edge eOrig = *it;

		int eSubGraph = 0;  // edgeSubGraph-data of eOrig
		if(edgeSubGraph!=0) eSubGraph = (*edgeSubGraph)[eOrig];

		SList<adjEntry> crossed;
		if(costOrig != 0) {
			findShortestPath(PG, E, *costOrig,
				PG.copy(eOrig->source()),PG.copy(eOrig->target()),
				forbidCrossingGens ? ((const PlanRepUML&)PG).typeOrig(eOrig) : Graph::association,
				crossed, edgeSubGraph, eSubGraph);
		} else {
			findShortestPath(E,
				PG.copy(eOrig->source()),PG.copy(eOrig->target()),
				forbidCrossingGens ? ((const PlanRepUML&)PG).typeOrig(eOrig) : Graph::association,
				crossed);
		}

		insertEdge(PG,E,eOrig,crossed,forbidCrossingGens,forbiddenEdgeOrig);
		
		if(removeReinsert() == rrIncremental) {
			currentOrigEdges.pushBack(eOrig);

			bool improved;
			do {
				++m_runsPostprocessing;
				improved = false;
				
				SListConstIterator<edge> itRR;
				for(itRR = currentOrigEdges.begin(); itRR.valid(); ++itRR)
				{
					edge eOrigRR = *itRR;
		
					int pathLength;
					if(costOrig != 0)
						pathLength = costCrossed(eOrigRR,PG,*costOrig,edgeSubGraph);
					else
						pathLength = PG.chain(eOrigRR).size() - 1;
					if (pathLength == 0) continue; // cannot improve
		
					removeEdge(PG,E,eOrigRR,forbidCrossingGens,forbiddenEdgeOrig);
		
					// try to find a better insertion path
					SList<adjEntry> crossed;
					if(costOrig != 0) {
						int eSubGraph = 0;  // edgeSubGraph-data of eOrig
						if(edgeSubGraph!=0) eSubGraph = (*edgeSubGraph)[eOrigRR];

						findShortestPath(PG, E, *costOrig,
							PG.copy(eOrigRR->source()),PG.copy(eOrigRR->target()),
							forbidCrossingGens ? ((const PlanRepUML&)PG).typeOrig(eOrigRR) : Graph::association,
							crossed, edgeSubGraph, eSubGraph);
					} else {
						findShortestPath(E,
							PG.copy(eOrigRR->source()),PG.copy(eOrigRR->target()),
							forbidCrossingGens ? ((const PlanRepUML&)PG).typeOrig(eOrigRR) : Graph::association,
							crossed);
					}
					
					// re-insert edge (insertion path cannot be longer)
					insertEdge(PG,E,eOrigRR,crossed,forbidCrossingGens,forbiddenEdgeOrig);
		
					int newPathLength = (costOrig != 0) ? costCrossed(eOrigRR,PG,*costOrig,edgeSubGraph) : (PG.chain(eOrigRR).size() - 1);
					OGDF_ASSERT(newPathLength <= pathLength);
					
					if(newPathLength < pathLength)
						improved = true;
				}
			} while (improved);
		}
	}

	const Graph &G = PG.original();
	if(removeReinsert() != rrIncremental) {
		// postprocessing (remove-reinsert heuristc)
		SListPure<edge> rrEdges;
	
		switch(removeReinsert())
		{
		case rrAll:
		case rrMostCrossed: {
				const List<node> &origInCC = PG.nodesInCC();
				ListConstIterator<node> itV;
	
				for(itV = origInCC.begin(); itV.valid(); ++itV) {
					node vG = *itV;
					adjEntry adj;
					forall_adj(adj,vG) {
						if ((adj->index() & 1) == 0) continue;
						edge eG = adj->theEdge();
						rrEdges.pushBack(eG);
					}
				}
			}
			break;
	
		case rrInserted:
			for(ListConstIterator<edge> it = origEdges.begin(); it.valid(); ++it)
				rrEdges.pushBack(*it);
			break;

		case rrNone:
		case rrIncremental:
			break;
		}
	
		// marks the end of the interval of rrEdges over which we iterate
		// initially set to invalid iterator which means all edges
		SListConstIterator<edge> itStop;
	
		bool improved;
		do {
			// abort postprocessing if time limit reached
			if (m_timeLimit >= 0 && m_timeLimit <= usedTime(T)) {
				retValue = retTimeoutFeasible;
				break;
			}
				
			++m_runsPostprocessing;
			improved = false;
	
			if(removeReinsert() == rrMostCrossed)
			{
				FEICrossingsBucket bucket(&PG);
				rrEdges.bucketSort(bucket);
	
				const int num = int(0.01 * percentMostCrossed() * G.numberOfEdges());
				itStop = rrEdges.get(num);
			}
	
			SListConstIterator<edge> it;
			for(it = rrEdges.begin(); it != itStop; ++it)
			{
				edge eOrig = *it;
							
				// remove only if crossings on edge;
				// in especially: forbidden edges are never handled by postprocessing
				//   since there are no crossings on such edges
				int pathLength;
				if(costOrig != 0)
					pathLength = costCrossed(eOrig,PG,*costOrig,edgeSubGraph);
				else
					pathLength = PG.chain(eOrig).size() - 1;
				if (pathLength == 0) continue; // cannot improve
	
				removeEdge(PG,E,eOrig,forbidCrossingGens,forbiddenEdgeOrig);
	
				// try to find a better insertion path
				SList<adjEntry> crossed;
				if(costOrig != 0) {
					int eSubGraph = 0;  // edgeSubGraph-data of eOrig
					if(edgeSubGraph!=0) eSubGraph = (*edgeSubGraph)[eOrig];

					findShortestPath(PG, E, *costOrig,
						PG.copy(eOrig->source()),PG.copy(eOrig->target()),
						forbidCrossingGens ? ((const PlanRepUML&)PG).typeOrig(eOrig) : Graph::association,
						crossed, edgeSubGraph, eSubGraph);
				} else {
					findShortestPath(E,
						PG.copy(eOrig->source()),PG.copy(eOrig->target()),
						forbidCrossingGens ? ((const PlanRepUML&)PG).typeOrig(eOrig) : Graph::association,
						crossed);
				}
	
				// re-insert edge (insertion path cannot be longer)
				insertEdge(PG,E,eOrig,crossed,forbidCrossingGens,forbiddenEdgeOrig);
	
				int newPathLength = (costOrig != 0) ? costCrossed(eOrig,PG,*costOrig,edgeSubGraph) : (PG.chain(eOrig).size() - 1);
				OGDF_ASSERT(newPathLength <= pathLength);
				
				if(newPathLength < pathLength)
					improved = true;
			}
		} while(improved); // iterate as long as we improve
	}
예제 #6
0
Module::ReturnType SubgraphPlanarizer::doCall(
	PlanRep &pr,
	int      cc,
	const EdgeArray<int>      *pCostOrig,
	const EdgeArray<bool>     *pForbiddenOrig,
	const EdgeArray<__uint32> *pEdgeSubGraphs,
	int                       &crossingNumber)
{
	OGDF_ASSERT(m_permutations >= 1);

	PlanarSubgraphModule &subgraph = m_subgraph.get();
	EdgeInsertionModule  &inserter = m_inserter.get();

	int nThreads = min(m_maxThreads, m_permutations);

	__int64 startTime;
	System::usedRealTime(startTime);
	__int64 stopTime = (m_timeLimit >= 0) ? (startTime + __int64(1000.0*m_timeLimit)) : -1;

	//
	// Compute subgraph
	//
	if(m_setTimeout)
		subgraph.timeLimit(m_timeLimit);

	pr.initCC(cc);

	List<edge> delEdges;
	ReturnType retValue;

	if(pCostOrig) {
		EdgeArray<int> costPG(pr);
		edge e;
		forall_edges(e,pr)
			costPG[e] = (*pCostOrig)[pr.original(e)];

		retValue = subgraph.call(pr, costPG, delEdges);
	} else
		retValue = subgraph.call(pr, delEdges);

	if(isSolution(retValue) == false)
		return retValue;

	const int m = delEdges.size();
	if(m == 0)
		return retOptimal;  // graph is planar

	for(ListIterator<edge> it = delEdges.begin(); it.valid(); ++it)
		*it = pr.original(*it);

	//
	// Permutation phase
	//

	int seed = rand();
#ifdef OGDF_HAVE_CPP11
	minstd_rand rng(seed);
#endif

	if(nThreads > 1) {
		//
		// Parallel implementation
		//
		ThreadMaster master(
			pr, cc,
			pCostOrig, pForbiddenOrig, pEdgeSubGraphs,
			delEdges,
			seed,
			m_permutations - nThreads,
			stopTime);

		Array<Worker *> thread(nThreads-1);
		for(int i = 0; i < nThreads-1; ++i) {
			thread[i] = new Worker(&master, inserter.clone());
			thread[i]->start();
		}

#ifdef OGDF_HAVE_CPP11
		doWorkHelper(master, inserter, rng);
#else
		doWorkHelper(master, inserter);
#endif

		for(int i = 0; i < nThreads-1; ++i) {
			thread[i]->join();
			delete thread[i];
		}

		master.restore(pr, crossingNumber);

	} else {
		//
		// Sequential implementation
		//
		PlanRepLight prl(pr);

		Array<edge> deletedEdges(m);
		int j = 0;
		for(ListIterator<edge> it = delEdges.begin(); it.valid(); ++it)
			deletedEdges[j++] = *it;

		bool foundSolution = false;
		CrossingStructure cs;
		for(int i = 1; i <= m_permutations; ++i)
		{
			int cr;
			bool ok = doSinglePermutation(prl, cc, pCostOrig, pForbiddenOrig, pEdgeSubGraphs, deletedEdges, inserter,
#ifdef OGDF_HAVE_CPP11
				rng,
#endif
				cr);

			if(ok && (foundSolution == false || cr < cs.weightedCrossingNumber())) {
				foundSolution = true;
				cs.init(prl, cr);
			}

			if(stopTime >= 0 && System::realTime() >= stopTime) {
				if(foundSolution == false)
					return retTimeoutInfeasible; // not able to find a solution...
				break;
			}
		}

		cs.restore(pr,cc); // restore best solution in pr
		crossingNumber = cs.weightedCrossingNumber();

		OGDF_ASSERT(isPlanar(pr) == true);
	}

	return retFeasible;
}
예제 #7
0
Module::ReturnType SubgraphPlanarizer::doCall(PlanRep &PG,
	int cc,
	const EdgeArray<int>  &cost,
	const EdgeArray<bool> &forbid,
	const EdgeArray<unsigned int>  &subgraphs,
	int& crossingNumber)
{
	OGDF_ASSERT(m_permutations >= 1);
  
	OGDF_ASSERT(!(useSubgraphs()) || useCost()); // ersetze durch exception handling

	double startTime;
	usedTime(startTime);

	if(m_setTimeout)
		m_subgraph.get().timeLimit(m_timeLimit);

	List<edge> deletedEdges;
	PG.initCC(cc);
	EdgeArray<int> costPG(PG);
	edge e;
	forall_edges(e,PG)
		costPG[e] = cost[PG.original(e)];
	ReturnType retValue = m_subgraph.get().call(PG, costPG, deletedEdges);
	if(isSolution(retValue) == false)
		return retValue;

	for(ListIterator<edge> it = deletedEdges.begin(); it.valid(); ++it)
		*it = PG.original(*it);

	bool foundSolution = false;
	CrossingStructure cs;
	for(int i = 1; i <= m_permutations; ++i)
	{
		const int nG = PG.numberOfNodes();
		
		for(ListConstIterator<edge> it = deletedEdges.begin(); it.valid(); ++it)
			PG.delCopy(PG.copy(*it));

		deletedEdges.permute();
	
		if(m_setTimeout)
			m_inserter.get().timeLimit(
				(m_timeLimit >= 0) ? max(0.0,m_timeLimit - usedTime(startTime)) : -1);
		
		ReturnType ret;
		if(useForbid()) {
			if(useCost()) {
				if(useSubgraphs())
					ret = m_inserter.get().call(PG, cost, forbid, deletedEdges, subgraphs);
				else
					ret = m_inserter.get().call(PG, cost, forbid, deletedEdges);
			} else
				ret = m_inserter.get().call(PG, forbid, deletedEdges);
		} else {
			if(useCost()) {	
				if(useSubgraphs())
					ret = m_inserter.get().call(PG, cost, deletedEdges, subgraphs);
				else
					ret = m_inserter.get().call(PG, cost, deletedEdges);
			} else
				ret = m_inserter.get().call(PG, deletedEdges);
		}

		if(isSolution(ret) == false)
			continue; // no solution found, that's bad...
	
		if(!useCost())
			crossingNumber = PG.numberOfNodes() - nG;
		else {
			crossingNumber = 0;
			node n;
			forall_nodes(n, PG) {
				if(PG.original(n) == 0) { // dummy found -> calc cost
					edge e1 = PG.original(n->firstAdj()->theEdge());
					edge e2 = PG.original(n->lastAdj()->theEdge());
					if(useSubgraphs()) {
						int subgraphCounter = 0;
						for(int i=0; i<32; i++) {
							if(((subgraphs[e1] & (1<<i))!=0) && ((subgraphs[e2] & (1<<i)) != 0))
								subgraphCounter++;
						}
						crossingNumber += (subgraphCounter*cost[e1] * cost[e2]);
					} else
						crossingNumber += cost[e1] * cost[e2];
				}
			}
		}
		
		if(i == 1 || crossingNumber < cs.weightedCrossingNumber()) {
			foundSolution = true;
			cs.init(PG, crossingNumber);
		}
		
		if(localLogMode() == LM_STATISTIC) {
			if(m_permutations <= 200 ||
				i <= 10 || (i <= 30 && (i % 2) == 0) || (i > 30 && i <= 100 && (i % 5) == 0) || ((i % 10) == 0))
				sout() << "\t" << cs.weightedCrossingNumber();
		}
		
		PG.initCC(cc);

		if(m_timeLimit >= 0 && usedTime(startTime) >= m_timeLimit) {
			if(foundSolution == false)
				return retTimeoutInfeasible; // not able to find a solution...
			break;
		}
	}
	
	cs.restore(PG,cc); // restore best solution in PG
	crossingNumber = cs.weightedCrossingNumber();
	
	PlanarModule pm;
	OGDF_ASSERT(pm.planarityTest(PG) == true);
	
	return retFeasible;
}