void parallelFreeSort(const Graph &G, SListPure<edge> &edges) { G.allEdges(edges); BucketSourceIndex bucketSrc; edges.bucketSort(0,G.maxNodeIndex(),bucketSrc); BucketTargetIndex bucketTgt; edges.bucketSort(0,G.maxNodeIndex(),bucketTgt); }
// compute the separated DFS children for all nodes in ascending order of // their lowpoint values in linear time void BoyerMyrvoldInit::computeDFSChildLists() { // Bucketsort by lowpoint values BucketLowPoint blp(m_lowPoint); // copy all non-virtual nodes in a list and sort them with Bucketsort SListPure<node> allNodes; for (node v : m_g.nodes) { if (m_dfi[v] > 0) allNodes.pushBack(v); } allNodes.bucketSort(1, m_nodeFromDFI.high(), blp); // build DFS-child list for (node v : allNodes) { OGDF_ASSERT(m_dfi[v] > 0); // if node is not root: insert node after last element of parent's DFSChildList // to achieve constant time deletion later: // set a pointer for each node to predecessor of his representative in the list if (m_adjParent[v] != nullptr) { OGDF_ASSERT(m_realVertex[m_adjParent[v]->theNode()] != nullptr); m_pNodeInParent[v] = m_separatedDFSChildList[m_realVertex[m_adjParent[v]->theNode()]].pushBack(v); OGDF_ASSERT(m_pNodeInParent[v].valid()); OGDF_ASSERT(v == *m_pNodeInParent[v]); } else m_pNodeInParent[v] = nullptr; } }
void parallelFreeSortUndirected(const Graph &G, SListPure<edge> &edges, EdgeArray<int> &minIndex, EdgeArray<int> &maxIndex) { G.allEdges(edges); for(edge e : G.edges) { int srcIndex = e->source()->index(), tgtIndex = e->target()->index(); if (srcIndex <= tgtIndex) { minIndex[e] = srcIndex; maxIndex[e] = tgtIndex; } else { minIndex[e] = tgtIndex; maxIndex[e] = srcIndex; } } BucketEdgeArray bucketMin(minIndex), bucketMax(maxIndex); edges.bucketSort(0,G.maxNodeIndex(),bucketMin); edges.bucketSort(0,G.maxNodeIndex(),bucketMax); }
// remove "arcs" from visibArcs which we already have in the constraint graph // (as basic arcs) void CompactionConstraintGraphBase::removeRedundantVisibArcs( SListPure<Tuple2<node,node> > &visibArcs) { // bucket sort list of all edges SListPure<edge> all; allEdges(all); parallelFreeSort(*this,all); // bucket sort visibArcs BucketFirstIndex bucketSrc; visibArcs.bucketSort(0,maxNodeIndex(),bucketSrc); BucketSecondIndex bucketTgt; visibArcs.bucketSort(0,maxNodeIndex(),bucketTgt); // now, in both lists, arcs are sorted by increasing target index, // and arcs with the same target index by increasing source index. SListConstIterator<edge> itAll = all.begin(); SListIterator<Tuple2<node,node> > it, itNext, itPrev; // for each arc in visibArcs, we check if it is also contained in list all for(it = visibArcs.begin(); it.valid(); it = itNext) { // required since we delete from the list we traverse itNext = it.succ(); int i = (*it).x1()->index(); int j = (*it).x2()->index(); // skip all arcs with smaller target index while(itAll.valid() && (*itAll)->target()->index() < j) ++itAll; // no more arcs => no more duplicates, so return if (!itAll.valid()) break; // if target index is j, we also skip all arcs with target index i // and source index smaller than i while(itAll.valid() && (*itAll)->target()->index() == j && (*itAll)->source()->index() < i) ++itAll; // no more arcs => no more duplicates, so return if (!itAll.valid()) break; // if (i,j) is already present, we delete it from visibArcs if ((*itAll)->source()->index() == i && (*itAll)->target()->index() == j) { //visibArcs.del(it); if (itPrev.valid()) visibArcs.delSucc(itPrev); else visibArcs.popFront(); } else itPrev = it; }//for visibArcs //****************************CHECK for //special treatment for cage visibility //two cases: input node cage: just compare arbitrary node // merger cage: check first if there are mergers itPrev = nullptr; for(it = visibArcs.begin(); it.valid(); it = itNext) { itNext = it.succ(); OGDF_ASSERT(!m_path[(*it).x1()].empty()); OGDF_ASSERT(!m_path[(*it).x1()].empty()); node boundRepresentant1 = m_path[(*it).x1()].front(); node boundRepresentant2 = m_path[(*it).x2()].front(); node en1 = m_pPR->expandedNode(boundRepresentant1); node en2 = m_pPR->expandedNode(boundRepresentant2); //do not allow visibility constraints in fixed cages //due to non-planarity with middle position constraints if ( ( en1 && en2 ) && ( en1 == en2) ) { if (itPrev.valid()) visibArcs.delSucc(itPrev); else visibArcs.popFront(); } else { //check if its a genmergerspanning vis arc, merge cases later node firstn = nullptr, secondn = nullptr; for (node n : m_path[(*it).x1()]) { node en = m_pPR->expandedNode(n); if (!en) continue; if (!(m_pPR->typeOf(n) == Graph::generalizationExpander)) continue; else { firstn = en; break; } }//for for (node n : m_path[(*it).x2()]) { node en = m_pPR->expandedNode(n); if (!en) continue; if (!(m_pPR->typeOf(n) == Graph::generalizationExpander)) continue; else { secondn = en; break; } }//for if ((firstn && secondn) && (firstn == secondn)) { if (itPrev.valid()) visibArcs.delSucc(itPrev); else visibArcs.popFront(); } else itPrev = it; } }//for visibArcs }
//--------------------------------------------------------- // 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 }
//-------------------------------------------------------------------- // 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; }
//-------------------------------------------------------------------- // 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; }