void FMMMLayout::call(GraphAttributes &GA, const EdgeArray<double> &edgeLength)
{
  const Graph &G = GA.constGraph();
  //tms t_total;//helping variable for time measure
  double t_total;
  NodeArray<NodeAttributes> A(G);       //stores the attributes of the nodes (given by L)
  EdgeArray<EdgeAttributes> E(G);       //stores the edge attributes of G
  Graph G_reduced;                      //stores a undirected simple and loopfree copy 
                                        //of G
  EdgeArray<EdgeAttributes> E_reduced;  //stores the edge attributes of G_reduced
  NodeArray<NodeAttributes> A_reduced;  //stores the node attributes of G_reduced 

  if(G.numberOfNodes() > 1)
    {
      GA.clearAllBends();//all are edges straight line
      if(useHighLevelOptions())
	update_low_level_options_due_to_high_level_options_settings();
      import_NodeAttributes(G,GA,A);
      import_EdgeAttributes(G,edgeLength,E);
      
      //times(&t_total);
	  usedTime(t_total);
      max_integer_position = pow(2.0,maxIntPosExponent());
      init_ind_ideal_edgelength(G,A,E);  
      make_simple_loopfree(G,A,E,G_reduced,A_reduced,E_reduced);
      call_DIVIDE_ET_IMPERA_step(G_reduced,A_reduced,E_reduced);
      if(allowedPositions() != apAll)
	make_positions_integer(G_reduced,A_reduced);
      //time_total = get_time(t_total);
	  time_total = usedTime(t_total);
            
      export_NodeAttributes(G_reduced,A_reduced,GA);
    }
  else //trivial cases
    { 
      if(G.numberOfNodes() == 1 )
	{
	  node v = G.firstNode();
	  GA.x(v) = 0;
	  GA.y(v) = 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

#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);
		}
Exemple #3
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
	}
Exemple #4
0
void Game::search()
{
        m_bSearching = true;
        m_bestMove = 0;
        m_bestValue = 0;
        m_bInterrupted = false;
	m_evalCount = 0;

        // 50 move rule and repetition check
        // no need to search if the game has allready ended
	if(m_board->isEnded()){
            m_bSearching = false;
            return;
        }


    	int move = searchDB();
	if(move != 0){

            m_bestMove = move;
            m_bSearching = false;

            return;
        }
	
	startTime();

	DEBUG_PRINT("Start alphabeta iterative deepening\n", 0);

        char buf[20];
        // reset principal variation for this search
        int i;
        for(i = 0; i < MAX_DEPTH; i++){

            m_arrPVMoves[i] = 0;
        }

	int reachedDepth = 0; boolean bContinue = true;
	for(m_searchDepth = 1; m_searchDepth < (MAX_DEPTH-QUIESCE_DEPTH); m_searchDepth++)
	{
            DEBUG_PRINT("Search at depth %d\n", m_searchDepth);

            bContinue = alphaBetaRoot(m_searchDepth, -ChessBoard::VALUATION_MATE, ChessBoard::VALUATION_MATE);

// todo -----------------------------------------------------------
//break; //debug


            if(bContinue){

#if DEBUG_LEVEL & 2
                DEBUG_PRINT("\n +-+-+-+-+-+-+-+-PV: ", 0);

                 for(i = 0; i < m_searchDepth; i++){

                    Move::toDbgString(m_arrPVMoves[i], buf);
                     DEBUG_PRINT(" > %s", buf);
                 }
                DEBUG_PRINT(" {%d}\n", m_bestValue);
#endif
                reachedDepth++;
                if(m_bestValue == ChessBoard::VALUATION_MATE){
                    DEBUG_PRINT("Found checkmate, stopping search\n", 0);
                    break;
                }
                // bail out if we're over 50% of time, next depth will take more than sum of previous
                if(usedTime()){
                        DEBUG_PRINT("Bailing out\n", 0);
                        break;
                }
            } else {

                if(m_bInterrupted){
                    DEBUG_PRINT("Interrupted search\n", 0);
                } else {
                    DEBUG_PRINT("No continuation, only one move\n", 0);
                }
                break;
            }
	}

//#if DEBUG_LEVEL & 3
	Move::toDbgString(m_bestMove, buf);
	DEBUG_PRINT("\n=====\nSearch\nvalue\t%d\nevalCnt\t%d\nMove\t%s\ndepth\t%d\nTime\t%ld ms\nNps\t%.2f\n", m_bestValue, m_evalCount, buf, reachedDepth, timePassed(), (double)m_evalCount / timePassed());
//#endif
        m_bSearching = false;
}
Exemple #5
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;
}
	//--------------------------------------------------------------------
	// actual algorithm call
	//--------------------------------------------------------------------
	Module::ReturnType VarEdgeInserterDynCore::call(
		const Array<edge> &origEdges,
		RemoveReinsertType rrPost,
		double percentMostCrossed)
	{
		double T;
		usedTime(T);

		Module::ReturnType retValue = Module::retFeasible;
		m_runsPostprocessing = 0;

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

		SListPure<edge> currentOrigEdges;

		if (rrPost == rrIncremental) {
			for (edge e : m_pr.edges)
				currentOrigEdges.pushBack(m_pr.original(e));

			// insertion of edges
			for (int i = origEdges.low(); i <= origEdges.high(); ++i)
			{
				edge eOrig = origEdges[i];
				storeTypeOfCurrentEdge(eOrig);

				m_pBC = createBCandSPQRtrees();
				SList<adjEntry> eip;
				insert(eOrig, eip);
				m_pr.insertEdgePath(eOrig, eip);
				delete m_pBC;

				currentOrigEdges.pushBack(eOrig);

				bool improved;
				do {
					++m_runsPostprocessing;
					improved = false;

					for (edge eOrigRR : currentOrigEdges)
					{
						int pathLength = (m_pCost != nullptr) ? costCrossed(eOrigRR) : (m_pr.chain(eOrigRR).size() - 1);
						if (pathLength == 0) continue; // cannot improve

						m_pr.removeEdgePath(eOrigRR);

						storeTypeOfCurrentEdge(eOrigRR);

						m_pBC = createBCandSPQRtrees();
						SList<adjEntry> eip;
						insert(eOrigRR, eip);
						m_pr.insertEdgePath(eOrigRR, eip);
						delete m_pBC;

						int newPathLength = (m_pCost != nullptr) ? costCrossed(eOrigRR) : (m_pr.chain(eOrigRR).size() - 1);
						OGDF_ASSERT(newPathLength <= pathLength);

						if (newPathLength < pathLength)
							improved = true;
					}
				} while (improved);
			}

		}
		else {

			// insertion of edges
			m_pBC = createBCandSPQRtrees();

			for (int i = origEdges.low(); i <= origEdges.high(); ++i)
			{
				edge eOrig = origEdges[i];
				storeTypeOfCurrentEdge(eOrig);

				SList<adjEntry> eip;
				insert(eOrig, eip);
				m_pBC->insertEdgePath(eOrig, eip);
			}

			delete m_pBC;

			// postprocessing (remove-reinsert heuristc)
			const int m = m_pr.original().numberOfEdges();
			SListPure<edge> rrEdges;

			switch (rrPost)
			{
			case rrAll:
			case rrMostCrossed:
				for (int i = m_pr.startEdge(); i < m_pr.stopEdge(); ++i)
					rrEdges.pushBack(m_pr.e(i));
				break;

			case rrInserted:
				for (int i = origEdges.low(); i <= origEdges.high(); ++i)
					rrEdges.pushBack(origEdges[i]);
				break;

			case rrNone:
			case rrIncremental:
			case rrIncInserted:
				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 = Module::retTimeoutFeasible;
					break;
				}

				++m_runsPostprocessing;
				improved = false;

				if (rrPost == rrMostCrossed)
				{
					VEICrossingsBucket bucket(&m_pr);
					rrEdges.bucketSort(bucket);

					const int num = int(0.01 * percentMostCrossed * m);
					itStop = rrEdges.get(num);
				}

				SListConstIterator<edge> it;
				for (it = rrEdges.begin(); it != itStop; ++it)
				{
					edge eOrig = *it;

					int pathLength = (m_pCost != nullptr) ? costCrossed(eOrig) : (m_pr.chain(eOrig).size() - 1);
					if (pathLength == 0) continue; // cannot improve

					m_pr.removeEdgePath(eOrig);

					storeTypeOfCurrentEdge(eOrig);

					m_pBC = createBCandSPQRtrees();
					SList<adjEntry> eip;
					insert(eOrig, eip);
					m_pr.insertEdgePath(eOrig, eip);
					delete m_pBC;

					// we cannot find a shortest path that is longer than before!
					int newPathLength = (m_pCost != nullptr) ? costCrossed(eOrig) : (m_pr.chain(eOrig).size() - 1);
					OGDF_ASSERT(newPathLength <= pathLength);

					if (newPathLength < pathLength)
						improved = true;
				}

			} while (improved);
		}


#ifdef OGDF_DEBUG
		bool isPlanar =
#endif
			planarEmbed(m_pr);

		OGDF_ASSERT(isPlanar);

		m_pr.removePseudoCrossings();
		OGDF_ASSERT(m_pr.representsCombEmbedding());

		return retValue;
	}
Exemple #7
0
	//--------------------------------------------------------------------
	// actual algorithm call
	//--------------------------------------------------------------------
	Module::ReturnType FixEdgeInserterCore::call(
		const Array<edge> &origEdges,
		bool keepEmbedding,
		RemoveReinsertType rrPost,
		double percentMostCrossed)
	{
		double T;
		usedTime(T);

		Module::ReturnType retValue = Module::retFeasible;
		m_runsPostprocessing = 0;

		if(!keepEmbedding) m_pr.embed();
		OGDF_ASSERT(m_pr.representsCombEmbedding() == true);

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

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

		init(E);
		constructDual(E);

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

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

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

		SListPure<edge> currentOrigEdges;
		if(rrPost == rrIncremental) {
			for(edge e : m_pr.edges)
				currentOrigEdges.pushBack(m_pr.original(e));
		}

		// insertion of edges
		bool doIncrementalPostprocessing =
			( rrPost == rrIncremental || rrPost == rrIncInserted );
		for(int i = origEdges.low(); i <= origEdges.high(); ++i)
		{
			edge eOrig = origEdges[i];
			storeTypeOfCurrentEdge(eOrig);
			//int eSubGraph = 0;  // edgeSubGraphs-data of eOrig
			//if(edgeSubGraphs!=0) eSubGraph = (*edgeSubGraphs)[eOrig];

			SList<adjEntry> crossed;
			if(m_pCost != nullptr) {
				findWeightedShortestPath(E, eOrig, crossed);
			} else {
				findShortestPath(E, eOrig, crossed);
			}

			insertEdge(E, eOrig, crossed);

			if(doIncrementalPostprocessing) {
				currentOrigEdges.pushBack(eOrig);

				bool improved;
				do {
					++m_runsPostprocessing;
					improved = false;

					for (edge eOrigRR : currentOrigEdges)
					{
						int pathLength = (m_pCost != nullptr) ? costCrossed(eOrigRR) : (m_pr.chain(eOrigRR).size() - 1);
						if (pathLength == 0) continue; // cannot improve

						removeEdge(E, eOrigRR);

						storeTypeOfCurrentEdge(eOrigRR);

						// try to find a better insertion path
						SList<adjEntry> crossed;
						if(m_pCost != nullptr) {
							findWeightedShortestPath(E, eOrigRR, crossed);
						} else {
							findShortestPath(E, eOrigRR, crossed);
						}

						// re-insert edge (insertion path cannot be longer)
						insertEdge(E, eOrigRR, crossed);

						int newPathLength = (m_pCost != nullptr) ? costCrossed(eOrigRR) : (m_pr.chain(eOrigRR).size() - 1);
						OGDF_ASSERT(newPathLength <= pathLength);

						if(newPathLength < pathLength)
							improved = true;
					}
				} while (improved);
			}
		}

		if(!doIncrementalPostprocessing) {
			// postprocessing (remove-reinsert heuristc)
			const int m = m_pr.original().numberOfEdges();
			SListPure<edge> rrEdges;

			switch(rrPost)
			{
			case rrAll:
			case rrMostCrossed:
				for(int i = m_pr.startEdge(); i < m_pr.stopEdge(); ++i)
					rrEdges.pushBack(m_pr.e(i));
				break;

			case rrInserted:
				for(int i = origEdges.low(); i <= origEdges.high(); ++i)
					rrEdges.pushBack(origEdges[i]);
				break;

			case rrNone:
			case rrIncremental:
			case rrIncInserted:
				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 = Module::retTimeoutFeasible;
					break;
				}

				++m_runsPostprocessing;
				improved = false;

				if(rrPost == rrMostCrossed)
				{
					FEICrossingsBucket bucket(&m_pr);
					rrEdges.bucketSort(bucket);

					const int num = int(0.01 * percentMostCrossed * m);
					itStop = rrEdges.get(num);
				}

				SListConstIterator<edge> it;
				for(it = rrEdges.begin(); it != itStop; ++it)
				{
					edge eOrig = *it;

					int pathLength = (m_pCost != nullptr) ? costCrossed(eOrig) : (m_pr.chain(eOrig).size() - 1);
					if (pathLength == 0) continue; // cannot improve

					removeEdge(E, eOrig);

					storeTypeOfCurrentEdge(eOrig);

					// try to find a better insertion path
					SList<adjEntry> crossed;
					if(m_pCost != nullptr) {
						findWeightedShortestPath(E, eOrig, crossed);
					} else {
						findShortestPath(E, eOrig, crossed);
					}

					// re-insert edge (insertion path cannot be longer)
					insertEdge(E, eOrig, crossed);

					// we cannot find a shortest path that is longer than before!
					int newPathLength = (m_pCost != nullptr) ? costCrossed(eOrig) : (m_pr.chain(eOrig).size() - 1);
					OGDF_ASSERT(newPathLength <= pathLength);

					if(newPathLength < pathLength)
						improved = true;
				}
			} while (improved);
		}

		// verify computed planarization
		OGDF_ASSERT(m_pr.representsCombEmbedding());

		// free resources
		cleanup();

		return retValue;
	}