void FMMLayout::call(GraphAttributes &AG) { const Graph &G = AG.constGraph(); EdgeArray<double> edgelength(G); edge e; forall_edges(e,G) edgelength[e] = 1.0; call(AG,edgelength); }
//************************************************************* // adds some color to the edges void SimDrawColorizer::addColor() { m_SD->addAttribute(GraphAttributes::edgeGraphics); m_SD->addAttribute(GraphAttributes::edgeColor); SimDrawColorScheme SDCS(m_colorScheme, m_SD->numberOfBasicGraphs()); edge e; forall_edges(e,*m_G) m_GA->colorEdge(e) = SDCS.getColor(m_GA->subGraphBits(e), m_SD->numberOfBasicGraphs()); } // end addColor
TricComp::TricComp (const Graph& G) : m_ESTACK(G.numberOfEdges()) { m_pGC = new GraphCopySimple(G); GraphCopySimple &GC = *m_pGC; const int n = GC.numberOfNodes(); const int m = GC.numberOfEdges(); #ifdef TRIC_COMP_OUTPUT cout << "Dividing G into triconnected components.\n" << endl; cout << "n = " << n << ", m = " << m << endl << endl; #endif m_component = Array<CompStruct>(3*m-6); m_numComp = 0; // special cases OGDF_ASSERT(n >= 2); OGDF_ASSERT_IF(dlExtendedChecking, isBiconnected(G)); if (n <= 2) { OGDF_ASSERT(m >= 3); CompStruct &C = newComp(); edge e; forall_edges(e,GC) C << e; C.m_type = bond; return; } m_TYPE.init(GC,unseen); splitMultiEdges(); // initialize arrays m_NUMBER.init(GC,0); m_LOWPT1.init(GC); m_LOWPT2.init(GC); m_FATHER.init(GC,0); m_ND .init(GC); m_DEGREE.init(GC); m_TREE_ARC.init(GC,0); m_NODEAT = Array<node>(1,n); m_numCount = 0; m_start = GC.firstNode(); DFS1(GC,m_start,0); edge e; forall_edges(e,GC) { bool up = (m_NUMBER[e->target()] - m_NUMBER[e->source()] > 0); if ((up && m_TYPE[e] == frond) || (!up && m_TYPE[e] == tree)) GC.reverseEdge(e); }
//--------------------------------------------------------- // 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 }
//************************************************************* // call for SubgraphPlanarizer // returns crossing number int SimDrawCaller::callSubgraphPlanarizer(int cc, int numberOfPermutations) { // transfer edge costs if existent EdgeArray<int> ec(*m_G, 1); if(m_GA->attributes() & GraphAttributes::edgeIntWeight) { edge e; forall_edges(e,*m_G) ec[e] = m_GA->intWeight(e); } // initialize updateESG(); int crossNum = 0; PlanRep PR(*m_G); // actual call for connected component cc SubgraphPlanarizer SP; VariableEmbeddingInserter* vei = new VariableEmbeddingInserter; vei->removeReinsert(rrIncremental); SP.setInserter(vei); SP.permutations(numberOfPermutations); SP.call(PR, cc, crossNum, &ec, 0, m_esg); // insert all dummy nodes into original graph *m_G NodeArray<node> newOrigNode(PR); node vPR; forall_nodes(vPR, PR) { if(PR.isDummy(vPR)) { node vOrig = m_G->newNode(); newOrigNode[vPR] = vOrig; m_SD->isDummy(vOrig) = true; } else newOrigNode[vPR] = PR.original(vPR); //original nodes are saved } // insert all edges incident to dummy nodes into *m_G EdgeArray<bool> toBeDeleted(*m_G, false); EdgeArray<bool> visited(PR, false); forall_nodes(vPR, PR) { if(PR.isDummy(vPR)) { node vNewOrig = newOrigNode[vPR]; //lebt in *m_G edge e; forall_adj_edges(e, vPR) //lebt in PR { if(!visited[e]) { node w = e->opposite(vPR); //lebt in PR node wNewOrig = newOrigNode[w]; //lebt in *m_G edge eNewOrig = m_G->newEdge(vNewOrig,wNewOrig); m_GA->subGraphBits(eNewOrig) = m_GA->subGraphBits(PR.original(e)); toBeDeleted[PR.original(e)] = true; visited[e] = true; } } } }
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; }
void OptimalRanking::doCall( const Graph& G, NodeArray<int> &rank, EdgeArray<bool> &reversed, const EdgeArray<int> &length, const EdgeArray<int> &costOrig) { MinCostFlowReinelt 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); node v; forall_nodes(v,G) 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); edge e; forall_edges(e,GC) 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) { 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); forall_edges(e,GC) cost[e] = -length[GC.original(e)]; node v; forall_nodes(v,GC) { int s = 0; 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); forall_nodes(v,GC) rank[GC.original(v)] = dual[v]; }