void FaceSinkGraph::doInit() { const ConstCombinatorialEmbedding &E = *m_pE; NodeArray<node> sinkSwitch(E,nullptr); // corresponding node in F (if any) NodeArray<bool> isSinkSwitch(E,true); NodeArray<int> visited(E,-1); int faceNo = -1; for(face f : E.faces) { faceNo++; node faceNode = newNode(); m_originalFace[faceNode] = f; SListPure<node> nodesInF; adjEntry adj1 = f->firstAdj(), adj = adj1; do { node v = adj->theNode(); // if the graph is not biconnected, then node v can visited more than once if (visited[v] != faceNo) { nodesInF.pushBack(v); visited[v] = faceNo; } if (v == m_source) m_containsSource[faceNode] = true; isSinkSwitch[adj->theEdge()->source()] = false; adj = adj->twin()->cyclicPred(); } while (adj != adj1); SListConstIterator<node> it; for(it = nodesInF.begin(); it.valid(); ++it) { node v = *it; if(isSinkSwitch[v]) { if (sinkSwitch[v] == nullptr) { node vF = newNode(); m_originalNode[vF] = v; sinkSwitch[v] = vF; } newEdge(faceNode,sinkSwitch[v]); } } for(it = nodesInF.begin(); it.valid(); ++it) isSinkSwitch[*it] = true; } }
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); } } } }
void FaceSinkGraph::doInit() { const ConstCombinatorialEmbedding &E = *m_pE; NodeArray<node> sinkSwitch(E,0); // corresponding node in F (if any) NodeArray<bool> isSinkSwitch(E,true); face f; forall_faces(f,E) { node faceNode = newNode(); m_originalFace[faceNode] = f; SListPure<node> nodesInF; adjEntry adj1 = f->firstAdj(), adj = adj1; do { node v = adj->theNode(); nodesInF.pushBack(v); if (v == m_source) m_containsSource[faceNode] = true; isSinkSwitch[adj->theEdge()->source()] = false; adj = adj->twin()->cyclicPred(); } while (adj != adj1); SListConstIterator<node> it; for(it = nodesInF.begin(); it.valid(); ++it) { node v = *it; if(isSinkSwitch[v]) { if (sinkSwitch[v] == 0) { node vF = newNode(); m_originalNode[vF] = v; sinkSwitch[v] = vF; } newEdge(faceNode,sinkSwitch[v]); } } for(it = nodesInF.begin(); it.valid(); ++it) isSinkSwitch[*it] = true; }
KuratowskiConstraint::KuratowskiConstraint(ABA_MASTER *master, int nEdges, SListPure<nodePair> &ks) : ABA_CONSTRAINT(master, 0, ABA_CSENSE::Less, nEdges-1, true, false, true) { SListConstIterator<nodePair> it; for (it = ks.begin(); it.valid(); ++it) { m_subdivision.pushBack(*it); } }
// Initializes a PQTree by a set of leaves that will korrespond to // the set of Keys stored in leafKeys. int PlanarPQTree::Initialize(SListPure<PlanarLeafKey<IndInfo*>*> &leafKeys) { SListIterator<PlanarLeafKey<IndInfo*>* > it; SListPure<PQLeafKey<edge,IndInfo*,bool>*> castLeafKeys; for (it = leafKeys.begin(); it.valid(); ++it) castLeafKeys.pushBack((PQLeafKey<edge,IndInfo*,bool>*) *it); return PQTree<edge,IndInfo*,bool>::Initialize(castLeafKeys); }
// Reduction reduced a set of leaves determined by their keys stored // in leafKeys. Integer redNumber is for debugging only. bool PlanarPQTree::Reduction(SListPure<PlanarLeafKey<indInfo*>*> &leafKeys) { SListIterator<PlanarLeafKey<indInfo*>* > it; SListPure<PQLeafKey<edge,indInfo*,bool>*> castLeafKeys; for (it = leafKeys.begin(); it.valid(); ++it) castLeafKeys.pushBack((PQLeafKey<edge,indInfo*,bool>*) *it); return PQTree<edge,indInfo*,bool>::Reduction(castLeafKeys); }
void UpwardPlanarSubgraphSimple::call(const Graph &G, List<edge> &delEdges) { delEdges.clear(); // We construct an auxiliary graph H which represents the current upward // planar subgraph. Graph H; NodeArray<node> mapToH(G); for(node v : G.nodes) mapToH[v] = H.newNode(); // We currently support only single-source acyclic digraphs ... node s; hasSingleSource(G,s); OGDF_ASSERT(s != 0); OGDF_ASSERT(isAcyclic(G)); // We start with a spanning tree of G rooted at the single source. NodeArray<bool> visitedNode(G,false); SListPure<edge> treeEdges; dfsBuildSpanningTree(s,treeEdges,visitedNode); // Mark all edges in the spanning tree so they can be skipped in the // loop below and add (copies of) them to H. EdgeArray<bool> visitedEdge(G,false); SListConstIterator<edge> it; for(it = treeEdges.begin(); it.valid(); ++it) { edge eG = *it; visitedEdge[eG] = true; H.newEdge(mapToH[eG->source()],mapToH[eG->target()]); } // Add subsequently the remaining edges to H and test if the resulting // graph is still upward planar. If not, remove the edge again from H // and add it to delEdges. for(edge eG : G.edges) { if(visitedEdge[eG] == true) continue; edge eH = H.newEdge(mapToH[eG->source()],mapToH[eG->target()]); if (UpwardPlanarity::isUpwardPlanar_singleSource(H) == false) { H.delEdge(eH); delEdges.pushBack(eG); } } }
// Reduction reduced a set of leaves determined by their keys stored // in leafKeys. Integer redNumber is for debugging only. bool PlanarSubgraphPQTree:: Reduction(SListPure<PlanarLeafKey<whaInfo*>*> &leafKeys, SList<PQLeafKey<edge,whaInfo*,bool>*> &eliminatedKeys, int redNumber) { SListPure<PQLeafKey<edge,whaInfo*,bool>*> castLeafKeys; SListIterator<PlanarLeafKey<whaInfo*>* > it; for (it = leafKeys.begin(); it.valid(); ++it) { castLeafKeys.pushBack((PQLeafKey<edge,whaInfo*,bool>*) *it); #ifdef OGDF_DEBUG if (int(ogdf::debugLevel) >= int(dlHeavyChecks)) { cout << (*it)->print() << endl; } #endif } determineMinRemoveSequence(castLeafKeys,eliminatedKeys); removeEliminatedLeaves(eliminatedKeys); SListIterator<PQLeafKey<edge,whaInfo*,bool>* > itn = castLeafKeys.begin(); SListIterator<PQLeafKey<edge,whaInfo*,bool>* > itp = itn++; for (; itn.valid();) { if ((*itn)->nodePointer()->status()== WHA_DELETE) { itn++; castLeafKeys.delSucc(itp); } else itp = itn++; } if ((*castLeafKeys.begin())->nodePointer()->status() == WHA_DELETE) castLeafKeys.popFront(); return Reduce(castLeafKeys,redNumber); }
// Function ReplaceFullRoot either replaces the full root // or one full child of a partial root of a pertinent subtree // by a single P-node with leaves corresponding the keys stored in leafKeys. void PlanarSubgraphPQTree:: ReplaceFullRoot(SListPure<PlanarLeafKey<whaInfo*>*> &leafKeys) { PQLeaf<edge,whaInfo*,bool> *leafPtr = 0; // dummy PQInternalNode<edge,whaInfo*,bool> *nodePtr = 0; // dummy //PQNodeKey<edge,whaInfo*,bool> *nodeInfoPtr = 0; // dummy PQNode<edge,whaInfo*,bool> *currentNode = 0; // dummy SListIterator<PlanarLeafKey<whaInfo*>* > it; if (!leafKeys.empty() && leafKeys.front() == leafKeys.back()) { //ReplaceFullRoot: replace pertinent root by a single leaf leafPtr = OGDF_NEW PQLeaf<edge,whaInfo*,bool>(m_identificationNumber++, EMPTY,(PQLeafKey<edge,whaInfo*,bool>*)leafKeys.front()); exchangeNodes(m_pertinentRoot,(PQNode<edge,whaInfo*,bool>*) leafPtr); if (m_pertinentRoot == m_root) m_root = (PQNode<edge,whaInfo*,bool>*) leafPtr; } else if (!leafKeys.empty()) // at least two leaves { //replace pertinent root by a $P$-node if ((m_pertinentRoot->type() == P_NODE) || (m_pertinentRoot->type() == Q_NODE)) { nodePtr = (PQInternalNode<edge,whaInfo*,bool>*)m_pertinentRoot; nodePtr->type(P_NODE); nodePtr->status(PERTROOT); nodePtr->childCount(0); while (!fullChildren(m_pertinentRoot)->empty()) { currentNode = fullChildren(m_pertinentRoot)->popFrontRet(); removeChildFromSiblings(currentNode); } } else if (m_pertinentRoot->type() == LEAF) { nodePtr = OGDF_NEW PQInternalNode<edge,whaInfo*,bool>(m_identificationNumber++, P_NODE,EMPTY); exchangeNodes(m_pertinentRoot,nodePtr); } SListPure<PQLeafKey<edge,whaInfo*,bool>*> castLeafKeys; for (it = leafKeys.begin(); it.valid(); ++it) castLeafKeys.pushBack((PQLeafKey<edge,whaInfo*,bool>*) *it); addNewLeavesToTree(nodePtr,castLeafKeys); } }
bool isParallelFree(const Graph &G) { if (G.numberOfEdges() <= 1) return true; SListPure<edge> edges; parallelFreeSort(G,edges); SListConstIterator<edge> it = edges.begin(); edge ePrev = *it, e; for(it = ++it; it.valid(); ++it, ePrev = e) { e = *it; if (ePrev->source() == e->source() && ePrev->target() == e->target()) return false; } return true; }
int numParallelEdges(const Graph &G) { if (G.numberOfEdges() <= 1) return 0; SListPure<edge> edges; parallelFreeSort(G,edges); int num = 0; SListConstIterator<edge> it = edges.begin(); edge ePrev = *it, e; for(it = ++it; it.valid(); ++it, ePrev = e) { e = *it; if (ePrev->source() == e->source() && ePrev->target() == e->target()) ++num; } return num; }
bool isParallelFreeUndirected(const Graph &G) { if (G.numberOfEdges() <= 1) return true; SListPure<edge> edges; EdgeArray<int> minIndex(G), maxIndex(G); parallelFreeSortUndirected(G,edges,minIndex,maxIndex); SListConstIterator<edge> it = edges.begin(); edge ePrev = *it, e; for(it = ++it; it.valid(); ++it, ePrev = e) { e = *it; if (minIndex[ePrev] == minIndex[e] && maxIndex[ePrev] == maxIndex[e]) return false; } return true; }
// Function ReplaceFullRoot either replaces the full root // or one full child of a partial root of a pertinent subtree // by a single P-node with leaves corresponding the keys stored in leafKeys. void PlanarPQTree::ReplaceFullRoot(SListPure<PlanarLeafKey<indInfo*>*> &leafKeys) { if (!leafKeys.empty() && leafKeys.front() == leafKeys.back()) { //ReplaceFullRoot: replace pertinent root by a single leaf PQLeaf<edge,indInfo*,bool> *leafPtr = OGDF_NEW PQLeaf<edge,indInfo*,bool>(m_identificationNumber++, EMPTY,(PQLeafKey<edge,indInfo*,bool>*)leafKeys.front()); exchangeNodes(m_pertinentRoot,(PQNode<edge,indInfo*,bool>*) leafPtr); if (m_pertinentRoot == m_root) m_root = (PQNode<edge,indInfo*,bool>*) leafPtr; m_pertinentRoot = 0; // check for this emptyAllPertinentNodes } else if (!leafKeys.empty()) // at least two leaves { PQInternalNode<edge,indInfo*,bool> *nodePtr = 0; // dummy //replace pertinent root by a $P$-node if ((m_pertinentRoot->type() == PQNodeRoot::PNode) || (m_pertinentRoot->type() == PQNodeRoot::QNode)) { nodePtr = (PQInternalNode<edge,indInfo*,bool>*)m_pertinentRoot; nodePtr->type(PQNodeRoot::PNode); nodePtr->childCount(0); while (!fullChildren(m_pertinentRoot)->empty()) removeChildFromSiblings(fullChildren(m_pertinentRoot)->popFrontRet()); } else if (m_pertinentRoot->type() == PQNodeRoot::leaf) { nodePtr = OGDF_NEW PQInternalNode<edge,indInfo*,bool>(m_identificationNumber++, PQNodeRoot::PNode,EMPTY); exchangeNodes(m_pertinentRoot,nodePtr); m_pertinentRoot = 0; // check for this emptyAllPertinentNodes } SListPure<PQLeafKey<edge,indInfo*,bool>*> castLeafKeys; SListIterator<PlanarLeafKey<indInfo*>* > it; for (it = leafKeys.begin(); it.valid(); ++it) castLeafKeys.pushBack((PQLeafKey<edge,indInfo*,bool>*) *it); addNewLeavesToTree(nodePtr,castLeafKeys); } }
// builds expansion graph of i-th biconnected component of the original graph void ExpansionGraph::init(int i) { OGDF_ASSERT(0 <= i); OGDF_ASSERT(i <= m_component.high()); // remove previous component for(node v : nodes) { node vOrig = m_vOrig[v]; if (vOrig) m_vCopy[vOrig] = nullptr; } clear(); // create new component SListConstIterator<edge> it; for(it = m_component[i].begin(); it.valid(); ++it) { edge e = *it; edge eCopy = newEdge(getCopy(e->source()),getCopy(e->target())); m_eOrig[eCopy] = e; } // expand vertices for(node v : nodes) { if (original(v) && v->indeg() >= 1 && v->outdeg() >= 1) { node vPrime = newNode(); m_vRep[vPrime] = m_vOrig[v]; SListPure<edge> edges; v->outEdges(edges); SListConstIterator<edge> it; for(it = edges.begin(); it.valid(); ++it) moveSource(*it,vPrime); newEdge(v,vPrime); } } }
// test if graphAcyclicTest plus edges in tmpAugmented is acyclic // removes added edges again bool UpwardPlanarSubgraphSimple::checkAcyclic( GraphCopySimple &graphAcyclicTest, SList<Tuple2<node,node> > &tmpAugmented) { SListPure<edge> added; SListConstIterator<Tuple2<node,node> > it; for(it = tmpAugmented.begin(); it.valid(); ++it) added.pushBack(graphAcyclicTest.newEdge( graphAcyclicTest.copy((*it).x1()), graphAcyclicTest.copy((*it).x2()))); bool acyclic = isAcyclic(graphAcyclicTest); SListConstIterator<edge> itE; for(itE = added.begin(); itE.valid(); ++itE) graphAcyclicTest.delEdge(*itE); return acyclic; }
// original variant of st-augmentation // Inserts also new nodes representing faces into G. void FaceSinkGraph::stAugmentation( node h, // node corresponding to external face Graph &G, // original graph (not const) SList<node> &augmentedNodes, // list of augmented nodes SList<edge> &augmentedEdges) // list of augmented edges { SListPure<node> roots; for(node v : nodes) { node vOrig = m_originalNode[v]; if (vOrig != nullptr && vOrig->indeg() > 0 && vOrig->outdeg() > 0) roots.pushBack(v); } node vh = dfsStAugmentation(h,nullptr,G,augmentedNodes,augmentedEdges); SListConstIterator<node> it; for(it = roots.begin(); it.valid(); ++it) dfsStAugmentation(*it,nullptr,G,augmentedNodes,augmentedEdges); augmentedEdges.pushBack(G.newEdge(m_source,vh)); }
void OptimalRanking::call (const Graph& G, NodeArray<int> &rank) { List<edge> R; m_subgraph.get().call(G,R); EdgeArray<bool> reversed(G,false); for (edge e : R) reversed[e] = true; R.clear(); EdgeArray<int> length(G,1); if(m_separateMultiEdges) { SListPure<edge> edges; EdgeArray<int> minIndex(G), maxIndex(G); parallelFreeSortUndirected(G, edges, minIndex, maxIndex); SListConstIterator<edge> it = edges.begin(); if(it.valid()) { int prevSrc = minIndex[*it]; int prevTgt = maxIndex[*it]; for(it = it.succ(); it.valid(); ++it) { edge e = *it; if (minIndex[e] == prevSrc && maxIndex[e] == prevTgt) length[e] = 2; else { prevSrc = minIndex[e]; prevTgt = maxIndex[e]; } } } } EdgeArray<int> cost(G,1); doCall(G, rank, reversed, length, cost); }
// builds expansion graph of graph G // for debugging purposes only void ExpansionGraph::init(const Graph &G) { // remove previous component for(node v : nodes) { node vOrig = m_vOrig[v]; if (vOrig) m_vCopy[vOrig] = nullptr; } clear(); // create new component for(node v : G.nodes) getCopy(v); for(edge e : G.edges) { edge eCopy = newEdge(getCopy(e->source()),getCopy(e->target())); m_eOrig[eCopy] = e; } // expand vertices for(node v : nodes) { if (original(v) && v->indeg() >= 1 && v->outdeg() >= 1) { node vPrime = newNode(); SListPure<edge> edges; v->outEdges(edges); SListConstIterator<edge> it; for(it = edges.begin(); it.valid(); ++it) moveSource(*it,vPrime); newEdge(v,vPrime); } } }
// 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 }
void PlanRep::expandLowDegreeVertices(OrthoRep &OR) { for(node v : nodes) { if (!(isVertex(v)) || expandAdj(v) != nullptr) continue; SList<edge> adjEdges; SListPure<Tuple2<node,int> > expander; node u = v; bool firstTime = true; setExpandedNode(v, v); for(adjEntry adj : v->adjEdges) { adjEdges.pushBack(adj->theEdge()); if(!firstTime) u = newNode(); setExpandedNode(u, v); typeOf(u) = Graph::lowDegreeExpander; expander.pushBack(Tuple2<node,int>(u,OR.angle(adj))); firstTime = false; } SListConstIterator<Tuple2<node,int>> itn = expander.begin().succ(); for (SListConstIterator<edge> it = adjEdges.begin().succ(); it.valid(); ++it) { // Did we allocate enough dummy nodes? OGDF_ASSERT(itn.valid()); if ((*it)->source() == v) moveSource(*it,(*itn).x1()); else moveTarget(*it,(*itn).x1()); ++itn; } adjEntry adjPrev = v->firstAdj(); itn = expander.begin(); int nBends = (*itn).x2(); for (++itn; itn.valid(); ++itn) { edge e = newEdge(adjPrev,(*itn).x1()->firstAdj()); OR.bend(e->adjSource()).set(convexBend,nBends); OR.bend(e->adjTarget()).set(reflexBend,nBends); OR.angle(adjPrev) = 1; OR.angle(e->adjSource()) = 2; OR.angle(e->adjTarget()) = 1; nBends = (*itn).x2(); typeOf(e) = association; //??? setExpansionEdge(e, 2); adjPrev = (*itn).x1()->firstAdj(); } edge e = newEdge(adjPrev,v->lastAdj()); typeOf(e) = association; //??? setExpansionEdge(e, 2); expandAdj(v) = e->adjSource(); OR.bend(e->adjSource()).set(convexBend,nBends); OR.bend(e->adjTarget()).set(reflexBend,nBends); OR.angle(adjPrev) = 1; OR.angle(e->adjSource()) = 2; OR.angle(e->adjTarget()) = 1; } }//expandlowdegreevertices
void PlanRep::expand(bool lowDegreeExpand) { for(node v : nodes) { // Replace vertices with high degree by cages and // replace degree 4 vertices with two generalizations // adjacent in the embedding list by a cage. if ((v->degree() > 4) && (typeOf(v) != Graph::dummy) && !lowDegreeExpand) { edge e; //Set the type of the node v. It remains in the graph // as one of the nodes of the expanded face. typeOf(v) = Graph::highDegreeExpander; // Scan the list of edges of v to find the adjacent edges of v // according to the planar embedding. All except one edge // will get a new adjacent node SList<edge> adjEdges; {forall_adj_edges(e,v) adjEdges.pushBack(e); } //The first edge remains at v. remove it from the list. e = adjEdges.popFrontRet(); // Create the list of high degree expanders // We need degree(v)-1 of them to construct a face. // and set expanded Node to v setExpandedNode(v, v); SListPure<node> expander; for (int i = 0; i < v->degree()-1; i++) { node u = newNode(); typeOf(u) = Graph::highDegreeExpander; setExpandedNode(u, v); expander.pushBack(u); } // We move the target node of each ingoing generalization of v to a new // node stored in expander. // Note that, for each such edge e, the target node of the original // edge is then different from the original of the target node of e // (the latter is 0 because u is a new (dummy) node) SListConstIterator<node> itn; NodeArray<adjEntry> ar(*this); itn = expander.begin(); for (edge ei : adjEdges) { // Did we allocate enough dummy nodes? OGDF_ASSERT(itn.valid()); if (ei->source() == v) moveSource(ei,*itn); else moveTarget(ei,*itn); ar[*itn] = (*itn)->firstAdj(); ++itn; } ar[v] = v->firstAdj(); // Now introduce the circular list of new edges // forming the border of the merge face. Keep the embedding. adjEntry adjPrev = v->firstAdj(); // cout <<endl << "INTRODUCING CIRCULAR EDGES" << endl; for (node n : expander) { // cout << adjPrev << " " << (*itn)->firstAdj() << endl; e = Graph::newEdge(adjPrev,n->firstAdj()); setExpansionEdge(e, 2);//can be removed if edgetypes work properly setExpansion(e); setAssociation(e); typeOf(e) = association; //??? if (!expandAdj(v)) expandAdj(v) = e->adjSource(); adjPrev = n->firstAdj(); } e = newEdge(adjPrev,v->lastAdj()); typeOf(e) = association; //??? setExpansionEdge(e, 2);//can be removed if edgetypes work properly setAssociation(e); }//highdegree // Replace all vertices with degree > 2 by cages. else if (v->degree() >= 2 && typeOf(v) != Graph::dummy && lowDegreeExpand) { edge e; //Set the type of the node v. It remains in the graph // as one of the nodes of the expanded face. typeOf(v) = Graph::lowDegreeExpander; //high?? // Scan the list of edges of v to find the adjacent edges of v // according to the planar embedding. All except one edge // will get a new adjacent node SList<edge> adjEdges; {forall_adj_edges(e,v) adjEdges.pushBack(e); } //The first edge remains at v. remove it from the list. // Check if it is a generalization. e = adjEdges.popFrontRet(); // Create the list of high degree expanders // We need degree(v)-1 of them to construct a face. // and set expanded Node to v setExpandedNode(v, v); SListPure<node> expander; for (int i = 0; i < v->degree()-1; i++) { node u = newNode(); typeOf(u) = Graph::highDegreeExpander; setExpandedNode(u, v); expander.pushBack(u); } // We move the target node of each ingoing generalization of v to a new // node stored in expander. // Note that, for each such edge e, the target node of the original // edge is then different from the original of the target node of e // (the latter is 0 because u is a new (dummy) node) NodeArray<adjEntry> ar(*this); SListConstIterator<node> itn = expander.begin(); for (edge ei : adjEdges) { // Did we allocate enough dummy nodes? OGDF_ASSERT(itn.valid()); if (ei->source() == v) moveSource(ei,*itn); else moveTarget(ei,*itn); ar[*itn] = (*itn)->firstAdj(); ++itn; } ar[v] = v->firstAdj(); // Now introduce the circular list of new edges // forming the border of the merge face. Keep the embedding. adjEntry adjPrev = v->firstAdj(); for (node n : expander) { e = newEdge(adjPrev,n->firstAdj()); if (!expandAdj(v)) expandAdj(v) = e->adjSource(); typeOf(e) = association; //??? setExpansionEdge(e, 2); //new types setAssociation(e); //should be dummy type? setExpansion(e); adjPrev = n->firstAdj(); } e = newEdge(adjPrev,v->lastAdj()); typeOf(e) = association; //??? setExpansionEdge(e, 2); } } }//expand
void UpwardPlanarSubgraphSimple::call(GraphCopy &GC, List<edge> &delEdges) { const Graph &G = GC.original(); delEdges.clear(); // We construct an auxiliary graph H which represents the current upward // planar subgraph. Graph H; NodeArray<node> mapToH(G,nullptr); NodeArray<node> mapToG(H,nullptr); for(node v : G.nodes) mapToG[ mapToH[v] = H.newNode() ] = v; // We currently support only single-source acyclic digraphs ... node s; hasSingleSource(G,s); OGDF_ASSERT(s != 0); OGDF_ASSERT(isAcyclic(G)); // We start with a spanning tree of G rooted at the single source. NodeArray<bool> visitedNode(G,false); SListPure<edge> treeEdges; dfsBuildSpanningTree(s,treeEdges,visitedNode); // Mark all edges in the spanning tree so they can be skipped in the // loop below and add (copies of) them to H. EdgeArray<bool> visitedEdge(G,false); SListConstIterator<edge> it; for(it = treeEdges.begin(); it.valid(); ++it) { edge eG = *it; visitedEdge[eG] = true; H.newEdge(mapToH[eG->source()],mapToH[eG->target()]); } // Add subsequently the remaining edges to H and test if the resulting // graph is still upward planar. If not, remove the edge again from H // and add it to delEdges. SList<Tuple2<node,node> > augmented; GraphCopySimple graphAcyclicTest(G); for(edge eG : G.edges) { // already treated ? if(visitedEdge[eG] == true) continue; // insert edge into H edge eH = H.newEdge(mapToH[eG->source()],mapToH[eG->target()]); node superSink; SList<edge> augmentedEdges; if (UpwardPlanarity::upwardPlanarAugment_singleSource(H,superSink,augmentedEdges) == false) { // if H is no longer upward planar, remove eG from subgraph H.delEdge(eH); delEdges.pushBack(eG); } else { // add augmented edges as node-pair to tmpAugmented and remove // all augmented edges from H again SList<Tuple2<node,node> > tmpAugmented; SListConstIterator<edge> it; for(it = augmentedEdges.begin(); it.valid(); ++it) { node v = mapToG[(*it)->source()]; node w = mapToG[(*it)->target()]; if (v && w) tmpAugmented.pushBack(Tuple2<node,node>(v,w)); H.delEdge(*it); } if (mapToG[superSink] == nullptr) H.delNode(superSink); //**************************************************************** // The following is a simple workaround to assure the following // property of the upward planar subgraph: // The st-augmented upward planar subgraph plus the edges not // in the subgraph must be acyclic. (This is a special property // of the embedding, not the augmentation.) // The upward-planar embedding function gives us ANY upward-planar // embedding. We check if the property above holds with this // embedding. If it doesn't, we have actually no idea if another // embedding would do. // The better solution would be to incorporate the acyclicity // property into the upward-planarity test, but this is compicated. //**************************************************************** // test if original graph plus augmented edges is still acyclic if(checkAcyclic(graphAcyclicTest,tmpAugmented) == true) { augmented = tmpAugmented; } else { // if not, remove eG from subgraph H.delEdge(eH); delEdges.pushBack(eG); } } } // remove edges not in the subgraph from GC ListConstIterator<edge> itE; for(itE = delEdges.begin(); itE.valid(); ++itE) GC.delEdge(GC.copy(*itE)); // add augmented edges to GC SListConstIterator<Tuple2<node,node> > itP; for(itP = augmented.begin(); itP.valid(); ++itP) { node v = (*itP).x1(); node w = (*itP).x2(); GC.newEdge(GC.copy(v),GC.copy(w)); } // add super sink to GC node sGC = nullptr; SList<node> sinks; for(node v : GC.nodes) { if(v->indeg() == 0) sGC = v; if(v->outdeg() == 0) sinks.pushBack(v); } node superSinkGC = GC.newNode(); SListConstIterator<node> itV; for(itV = sinks.begin(); itV.valid(); ++itV) GC.newEdge(*itV,superSinkGC); // add st-edge to GC, so that we now have a planar st-digraph GC.newEdge(sGC,superSinkGC); OGDF_ASSERT(isAcyclic(GC)); OGDF_ASSERT(isPlanar(GC)); }
//-------------------------------------------------------------------- // 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; }
//--------------------------------------------------------- // 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 }
// separate pertinent nodes in the lists of possible different minor-types void FindKuratowskis::splitInMinorTypes( const SListPure<adjEntry>& externalFacePath, int marker) { // mark nodes, which are before stopX or behind stopY in CCW-traversal and add // all extern nodes strictly between stopX and stopY to list // externE for minor E (pertinent nodes are considered because of the // position of z left or right of w) SListConstIterator<adjEntry> itExtern; SListIterator<WInfo> it = k.wNodes.begin(); node x; bool between = false; SListPure<WInfo*> infoList; SListIterator<WInfo*> itList; ExternE externEdummy; // compute list of externE nodes for (itExtern=externalFacePath.begin(); itExtern.valid(); ++itExtern) { x = (*itExtern)->theNode(); if (x==k.stopX || x==k.stopY) { between = (between==false) ? true : false; } else { if (!between) { m_wasHere[x]=marker; } else { if (pBM->externallyActive(x,k.V_DFI)) { externEdummy.theNode = x; // check minor type B and save extern linkage if (it.valid() && (*it).w==x && !m_pertinentRoots[x].empty() && m_lowPoint[m_nodeFromDFI[-m_dfi[m_pertinentRoots[x].back()]]] < k.V_DFI) { WInfo& info(*it); // checking minor type B info.minorType |= WInfo::B; // mark extern node for later extraction externEdummy.startnodes.pushBack(0); // create externE-list k.externE.pushBack(externEdummy); // save extern linkage info.externEStart = k.externE.rbegin(); info.externEEnd = k.externE.rbegin(); } else { // create externE-list externEdummy.startnodes.clear(); k.externE.pushBack(externEdummy); } // save for each wNode the first externally active successor // on the external face for (itList = infoList.begin(); itList.valid(); ++itList) (*itList)->firstExternEAfterW = x; infoList.clear(); } // get appropriate WInfo if (it.valid() && (*it).w==x) { infoList.pushBack(&(*it)); ++it; } } } } // divide wNodes in different minor types // avoids multiple computation of the externE range itExtern = externalFacePath.begin(); SListIterator<ExternE> itExternE = k.externE.begin(); WInfo* oldInfo = NULL; for (it=k.wNodes.begin(); it.valid(); ++it) { WInfo& info(*it); // checking minor type A if (k.RReal!=k.V) info.minorType |= WInfo::A; // if a XYPath exists if (info.highestXYPath!=NULL) { if (m_wasHere[info.highestXYPath->front()->theNode()]==marker) info.pxAboveStopX = true; if (m_wasHere[info.highestXYPath->back()->theNode()]==marker) info.pyAboveStopY = true; // checking minor type C if (info.pxAboveStopX || info.pyAboveStopY) info.minorType |= WInfo::C; // checking minor type D if (info.zPath!=NULL) info.minorType |= WInfo::D; // checking minor type E if (!k.externE.empty()) { node t; // compute valid range of externE-nodes in linear time if (oldInfo!=NULL && info.highestXYPath==oldInfo->highestXYPath) { // found the same highestXYPath as before info.externEStart = oldInfo->externEStart; info.externEEnd = oldInfo->externEEnd; if (oldInfo->minorType & WInfo::E) info.minorType |= WInfo::E; } else { // compute range of a new highestXYPath node px; if (info.pxAboveStopX) px = k.stopX; else px = info.highestXYPath->front()->theNode(); node py; if (info.pyAboveStopY) py = k.stopY; else py = info.highestXYPath->back()->theNode(); while ((*itExtern)->theNode() != px) ++itExtern; t = (*(++itExtern))->theNode(); node start = NULL; node end = NULL; while (t != py) { if (pBM->externallyActive(t,k.V_DFI)) { if (start==NULL) start = t; end = t; } t = (*(++itExtern))->theNode(); } if (start != NULL) { while ((*itExternE).theNode != start) ++itExternE; info.externEStart = itExternE; // mark node to extract external subgraph later (*itExternE).startnodes.pushBack(0); node temp = start; while (temp != end) { temp = (*++itExternE).theNode; // mark node to extract external subgraph later (*itExternE).startnodes.pushBack(0); } info.externEEnd = itExternE; info.minorType |= WInfo::E; } oldInfo = &info; } } } /* // use this to find special kuratowski-structures if ((info.minorType & (WInfo::A|WInfo::B|WInfo::C|WInfo::D|WInfo::E)) == (WInfo::A|WInfo::B|WInfo::C|WInfo::D|WInfo::E)) { char t; cin >> t; } */ } // extract the externalSubgraph of all saved externally active nodes // exclude the already extracted minor b-types #ifdef OGDF_DEBUG int visited = m_nodeMarker+1; #endif for (itExternE=k.externE.begin(); itExternE.valid(); ++itExternE) { if ((*itExternE).startnodes.empty()) continue; ExternE& externE(*itExternE); externE.startnodes.clear(); if (m_bundles) { OGDF_ASSERT(m_wasHere[externE.theNode] < visited); extractExternalSubgraphBundles(externE.theNode,k.V_DFI, k.externalSubgraph,++m_nodeMarker); } else { extractExternalSubgraph(externE.theNode,k.V_DFI,externE.startnodes, externE.endnodes); SListIterator<int> itInt; SListPure<edge> dummy; for (itInt = externE.startnodes.begin(); itInt.valid(); ++itInt) externE.externalPaths.pushBack(dummy); } } }
void planarBiconnectedGraph(Graph &G, int n, int m, bool multiEdges) { if (n < 3) n = 3; if (m < n) m = n; if (m > 3*n-6) m = 3*n-6; int ke = n-3, kf = m-n; G.clear(); Array<edge> edges(m); Array<face> bigFaces(m); //random_source S; // we start with a triangle node v1 = G.newNode(), v2 = G.newNode(), v3 = G.newNode(); edges[0] = G.newEdge(v1,v2); edges[1] = G.newEdge(v2,v3); edges[2] = G.newEdge(v3,v1); CombinatorialEmbedding E(G); FaceArray<int> posBigFaces(E); int nBigFaces = 0, nEdges = 3; while(ke+kf > 0) { int p = randomNumber(1,ke+kf); if (nBigFaces == 0 || p <= ke) { edge e = edges[randomNumber(0,nEdges-1)]; face f = E.rightFace(e->adjSource()); face fr = E.rightFace(e->adjTarget()); edges[nEdges++] = E.split(e); if (f->size() == 4) { posBigFaces[f] = nBigFaces; bigFaces[nBigFaces++] = f; } if (fr->size() == 4) { posBigFaces[fr] = nBigFaces; bigFaces[nBigFaces++] = fr; } ke--; } else { int pos = randomNumber(0,nBigFaces-1); face f = bigFaces[pos]; int df = f->size(); int i = randomNumber(0,df-1), j = randomNumber(2,df-2); adjEntry adj1; for (adj1 = f->firstAdj(); i > 0; adj1 = adj1->faceCycleSucc()) i--; adjEntry adj2; for (adj2 = adj1; j > 0; adj2 = adj2->faceCycleSucc()) j--; edge e = E.splitFace(adj1,adj2); edges[nEdges++] = e; face f1 = E.rightFace(e->adjSource()); face f2 = E.rightFace(e->adjTarget()); bigFaces[pos] = f1; posBigFaces[f1] = pos; if (f2->size() >= 4) { posBigFaces[f2] = nBigFaces; bigFaces[nBigFaces++] = f2; } if (f1->size() == 3) { bigFaces[pos] = bigFaces[--nBigFaces]; } kf--; } } if (multiEdges == false) { SListPure<edge> allEdges; EdgeArray<int> minIndex(G), maxIndex(G); parallelFreeSortUndirected(G,allEdges,minIndex,maxIndex); SListConstIterator<edge> it = allEdges.begin(); edge ePrev = *it, e; for(it = ++it; it.valid(); ++it, ePrev = e) { e = *it; if (minIndex[ePrev] == minIndex[e] && maxIndex[ePrev] == maxIndex[e]) { G.move(e, e->adjTarget()->faceCycleSucc()->twin(), ogdf::before, e->adjSource()->faceCycleSucc()->twin(), ogdf::before); } } } }
void planarCNBGraph(Graph &G, int n, int m, int b) { G.clear(); if (b <= 0) b = 1; if (n <= 0) n = 1; if ((m <= 0) || (m > 3*n-6)) m = 3*n-6; node cutv; G.newNode(); for (int nB=1; nB<=b; nB++){ cutv = G.chooseNode(); // set number of nodes for the current created block int actN = randomNumber(1, n); node v1 = G.newNode(); if (actN <= 1){ G.newEdge(v1, cutv); } else if (actN == 2){ node v2 = G.newNode(); G.newEdge(v1, v2); int rnd = randomNumber(1, 2); edge newE; int rnd2 = randomNumber(1, 2); if (rnd == 1){ newE = G.newEdge(v1, cutv); } else{ newE = G.newEdge(v2, cutv); } if (rnd2 == 1){ G.contract(newE); } } else{ // set number of edges for the current created block int actM; if (m > 3*actN-6) actM = randomNumber(1, 3*actN-6); else actM = randomNumber(1, m); if (actM < actN) actM = actN; int ke = actN-3, kf = actM-actN; Array<node> nodes(actN); Array<edge> edges(actM); Array<face> bigFaces(actM); // we start with a triangle node v2 = G.newNode(), v3 = G.newNode(); nodes[0] = v1; nodes[1] = v2; nodes[2] = v3; edges[0] = G.newEdge(v1,v2); edges[1] = G.newEdge(v2,v3); edges[2] = G.newEdge(v3,v1); int actInsertedNodes = 3; CombinatorialEmbedding E(G); FaceArray<int> posBigFaces(E); int nBigFaces = 0, nEdges = 3; while(ke+kf > 0) { int p = randomNumber(1,ke+kf); if (nBigFaces == 0 || p <= ke) { int eNr = randomNumber(0,nEdges-1); edge e = edges[eNr]; face f = E.rightFace(e->adjSource()); face fr = E.rightFace(e->adjTarget()); node u = e->source(); node v = e->target(); edges[nEdges++] = E.split(e); if (e->source() != v && e->source() != u) nodes[actInsertedNodes++] = e->source(); else nodes[actInsertedNodes++] = e->target(); if (f->size() == 4) { posBigFaces[f] = nBigFaces; bigFaces[nBigFaces++] = f; } if (fr->size() == 4) { posBigFaces[fr] = nBigFaces; bigFaces[nBigFaces++] = fr; } ke--; } else { int pos = randomNumber(0,nBigFaces-1); face f = bigFaces[pos]; int df = f->size(); int i = randomNumber(0,df-1), j = randomNumber(2,df-2); adjEntry adj1; for (adj1 = f->firstAdj(); i > 0; adj1 = adj1->faceCycleSucc()) i--; adjEntry adj2; for (adj2 = adj1; j > 0; adj2 = adj2->faceCycleSucc()) j--; edge e = E.splitFace(adj1,adj2); edges[nEdges++] = e; face f1 = E.rightFace(e->adjSource()); face f2 = E.rightFace(e->adjTarget()); bigFaces[pos] = f1; posBigFaces[f1] = pos; if (f2->size() >= 4) { posBigFaces[f2] = nBigFaces; bigFaces[nBigFaces++] = f2; } if (f1->size() == 3) { bigFaces[pos] = bigFaces[--nBigFaces]; } kf--; } } // delete multi edges SListPure<edge> allEdges; EdgeArray<int> minIndex(G), maxIndex(G); parallelFreeSortUndirected(G,allEdges,minIndex,maxIndex); SListConstIterator<edge> it = allEdges.begin(); edge ePrev = *it, e; for(it = ++it; it.valid(); ++it, ePrev = e) { e = *it; if (minIndex[ePrev] == minIndex[e] && maxIndex[ePrev] == maxIndex[e]) { G.move(e, e->adjTarget()->faceCycleSucc()->twin(), ogdf::before, e->adjSource()->faceCycleSucc()->twin(), ogdf::before); } } node cutv2 = nodes[randomNumber(0,actN-1)]; int rnd = randomNumber(1,2); edge newE = G.newEdge(cutv2, cutv); if (rnd == 1){ G.contract(newE); } } } };
//-------------------------------------------------------------------- // 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; }
void print_edge_list(SListPure<edge> & list) { for (SListPure<edge>::iterator it = list.begin(); it.valid(); ++it) print_edge(*it); printf("\n"); }
void EmbedPQTree::ReplaceFullRoot( SListPure<PlanarLeafKey<indInfo*>*> &leafKeys, SListPure<PQBasicKey<edge,indInfo*,bool>*> &frontier, node v, bool addIndicator, PQNode<edge,indInfo*,bool> *opposite) { EmbedIndicator *newInd = 0; front(m_pertinentRoot,frontier); if (addIndicator) { indInfo *newInfo = OGDF_NEW indInfo(v); embedKey *nodeInfoPtr = OGDF_NEW embedKey(newInfo); newInd = OGDF_NEW EmbedIndicator(m_identificationNumber++, (PQNodeKey<edge,indInfo*,bool>*)nodeInfoPtr); newInd->setNodeInfo(nodeInfoPtr); nodeInfoPtr->setNodePointer(newInd); } if (!leafKeys.empty() && leafKeys.front() == leafKeys.back()) { //ReplaceFullRoot: replace pertinent root by a single leaf if (addIndicator) { opposite = m_pertinentRoot->getNextSib(opposite); if (!opposite) // m_pertinentRoot is endmost child { addNodeToNewParent(m_pertinentRoot->parent(),newInd, m_pertinentRoot,opposite); } else addNodeToNewParent(0,newInd,m_pertinentRoot,opposite); // Setting the sibling pointers into opposite direction of // scanning the front allows to track swaps of the indicator newInd->changeSiblings(m_pertinentRoot,0); newInd->changeSiblings(opposite,0); newInd->putSibling(m_pertinentRoot,LEFT); newInd->putSibling(opposite,RIGHT); } PQLeaf<edge,indInfo*,bool> *leafPtr = OGDF_NEW PQLeaf<edge,indInfo*,bool>(m_identificationNumber++, EMPTY,(PQLeafKey<edge,indInfo*,bool>*)leafKeys.front()); exchangeNodes(m_pertinentRoot,(PQNode<edge,indInfo*,bool>*) leafPtr); if (m_pertinentRoot == m_root) m_root = (PQNode<edge,indInfo*,bool>*) leafPtr; m_pertinentRoot = 0; // check for this emptyAllPertinentNodes } else if (!leafKeys.empty()) // at least two leaves { //replace pertinent root by a $P$-node if (addIndicator) { opposite = m_pertinentRoot->getNextSib(opposite); if (!opposite) // m_pertinentRoot is endmost child { addNodeToNewParent(m_pertinentRoot->parent(),newInd, m_pertinentRoot,opposite); } else addNodeToNewParent(0,newInd,m_pertinentRoot,opposite); // Setting the sibling pointers into opposite direction of // scanning the front allows to track swaps of the indicator newInd->changeSiblings(m_pertinentRoot,0); newInd->changeSiblings(opposite,0); newInd->putSibling(m_pertinentRoot,LEFT); newInd->putSibling(opposite,RIGHT); } PQInternalNode<edge,indInfo*,bool> *nodePtr = 0; // dummy if ((m_pertinentRoot->type() == PQNodeRoot::PNode) || (m_pertinentRoot->type() == PQNodeRoot::QNode)) { nodePtr = (PQInternalNode<edge,indInfo*,bool>*)m_pertinentRoot; nodePtr->type(PQNodeRoot::PNode); nodePtr->childCount(0); while (!fullChildren(m_pertinentRoot)->empty()) { PQNode<edge,indInfo*,bool> *currentNode = fullChildren(m_pertinentRoot)->popFrontRet(); removeChildFromSiblings(currentNode); } } else if (m_pertinentRoot->type() == PQNodeRoot::leaf) { nodePtr = OGDF_NEW PQInternalNode<edge,indInfo*,bool>(m_identificationNumber++, PQNodeRoot::PNode,EMPTY); exchangeNodes(m_pertinentRoot,nodePtr); m_pertinentRoot = 0; // check for this emptyAllPertinentNodes } SListPure<PQLeafKey<edge,indInfo*,bool>*> castLeafKeys; SListIterator<PlanarLeafKey<indInfo*>* > it; for (it = leafKeys.begin(); it.valid(); ++it) castLeafKeys.pushBack((PQLeafKey<edge,indInfo*,bool>*) *it); addNewLeavesToTree(nodePtr,castLeafKeys); } }