// extracts and adds external subgraph from stopnode to ancestors of the node with dfi root // to edgelist, nodeMarker is used as a visited flag. returns the endnode with lowest dfi. void FindKuratowskis::extractExternalSubgraph( const node stop, int root, SListPure<int>& externalStartnodes, SListPure<node>& externalEndnodes) { int lowpoint; ListConstIterator<node> it; if (m_leastAncestor[stop] < root) { externalStartnodes.pushBack(m_dfi[stop]); externalEndnodes.pushBack(m_nodeFromDFI[m_leastAncestor[stop]]); } // descent to external active child bicomps of stopnode node temp; for (it = m_separatedDFSChildList[stop].begin(); it.valid(); ++it) { temp = *it; lowpoint = m_lowPoint[temp]; if (lowpoint >= root) break; externalStartnodes.pushBack(m_dfi[temp]); externalEndnodes.pushBack(m_nodeFromDFI[lowpoint]); } }
// The function front scans the frontier of nodePtr. It returns the keys // of the leaves found in the frontier of nodePtr in a SListPure. // These keys include keys of direction indicators detected in the frontier. // // No direction is assigned to the direction indicators. // void EmbedPQTree::getFront( PQNode<edge,IndInfo*,bool>* nodePtr, SListPure<PQBasicKey<edge,IndInfo*,bool>*> &keys) { ArrayBuffer<PQNode<edge,IndInfo*,bool>*> S; S.push(nodePtr); while (!S.empty()) { PQNode<edge,IndInfo*,bool> *checkNode = S.popRet(); if (checkNode->type() == PQNodeRoot::PQNodeType::Leaf) keys.pushBack((PQBasicKey<edge,IndInfo*,bool>*) checkNode->getKey()); else { PQNode<edge,IndInfo*,bool>* firstSon = nullptr; if (checkNode->type() == PQNodeRoot::PQNodeType::PNode) { firstSon = checkNode->referenceChild(); } else if (checkNode->type() == PQNodeRoot::PQNodeType::QNode) { firstSon = checkNode->getEndmost(PQNodeRoot::SibDirection::Right); // By this, we make sure that we start on the left side // since the left endmost child will be on top of the stack } if (firstSon->status() == PQNodeRoot::PQNodeStatus::Indicator) { keys.pushBack((PQBasicKey<edge,IndInfo*,bool>*) firstSon->getNodeInfo()); } else S.push(firstSon); PQNode<edge,IndInfo*,bool> *nextSon = firstSon->getNextSib(nullptr); PQNode<edge,IndInfo*,bool> *oldSib = firstSon; while (nextSon && nextSon != firstSon) { if (nextSon->status() == PQNodeRoot::PQNodeStatus::Indicator) keys.pushBack((PQBasicKey<edge,IndInfo*,bool>*) nextSon->getNodeInfo()); else S.push(nextSon); PQNode<edge,IndInfo*,bool> *holdSib = nextSon->getNextSib(oldSib); oldSib = nextSon; nextSon = holdSib; } } } }
// The function front scans the frontier of nodePtr. It returns the keys // of the leaves found in the frontier of nodePtr in a SListPure. // These keys include keys of direction indicators detected in the frontier. // // No direction is assigned to the direction indicators. // void EmbedPQTree::getFront( PQNode<edge,indInfo*,bool>* nodePtr, SListPure<PQBasicKey<edge,indInfo*,bool>*> &keys) { Stack<PQNode<edge,indInfo*,bool>*> S; S.push(nodePtr); while (!S.empty()) { PQNode<edge,indInfo*,bool> *checkNode = S.pop(); if (checkNode->type() == PQNodeRoot::leaf) keys.pushBack((PQBasicKey<edge,indInfo*,bool>*) checkNode->getKey()); else { PQNode<edge,indInfo*,bool>* firstSon = 0; if (checkNode->type() == PQNodeRoot::PNode) { firstSon = checkNode->referenceChild(); } else if (checkNode->type() == PQNodeRoot::QNode) { firstSon = checkNode->getEndmost(RIGHT); // By this, we make sure that we start on the left side // since the left endmost child will be on top of the stack } if (firstSon->status() == INDICATOR) { keys.pushBack((PQBasicKey<edge,indInfo*,bool>*) firstSon->getNodeInfo()); } else S.push(firstSon); PQNode<edge,indInfo*,bool> *nextSon = firstSon->getNextSib(0); PQNode<edge,indInfo*,bool> *oldSib = firstSon; while (nextSon && nextSon != firstSon) { if (nextSon->status() == INDICATOR) keys.pushBack((PQBasicKey<edge,indInfo*,bool>*) nextSon->getNodeInfo()); else S.push(nextSon); PQNode<edge,indInfo*,bool> *holdSib = nextSon->getNextSib(oldSib); oldSib = nextSon; nextSon = holdSib; } } } }
// extract and add external subgraph from stopnode to ancestors of the node with dfi root // to edgelist, nodeMarker is used as a visited flag. returns the endnode with lowest dfi. void FindKuratowskis::extractExternalSubgraphBundles( const node stop, int root, SListPure<edge>& externalSubgraph, int nodeMarker) { node v,temp; adjEntry adj; #ifdef OGDF_DEBUG forall_nodes(v,m_g) OGDF_ASSERT(m_wasHere[v]!=nodeMarker); #endif StackPure<node> stack; // stack for dfs-traversal ListConstIterator<node> it; stack.push(stop); while (!stack.empty()) { v = stack.pop(); if (m_wasHere[v]==nodeMarker) continue; // mark visited nodes m_wasHere[v]=nodeMarker; // search for unvisited nodes and add them to stack forall_adj(adj,v) { temp = adj->twinNode(); if (m_edgeType[adj->theEdge()]==EDGE_BACK_DELETED) continue; // go along backedges to ancestor (ignore virtual nodes) if (m_dfi[temp] < root && m_dfi[temp] > 0) { OGDF_ASSERT(m_edgeType[adj->theEdge()]==EDGE_BACK); externalSubgraph.pushBack(adj->theEdge()); } else if (v != stop && m_dfi[temp]>=m_dfi[v]) { // set flag and push unvisited nodes OGDF_ASSERT(m_edgeType[adj->theEdge()]==EDGE_BACK || m_edgeType[adj->theEdge()]==EDGE_DFS || m_edgeType[adj->theEdge()]==EDGE_BACK_DELETED); externalSubgraph.pushBack(adj->theEdge()); if (m_wasHere[temp] != nodeMarker) stack.push(temp); } } // descent to external active child bicomps for (it = m_separatedDFSChildList[v].begin(); it.valid(); ++it) { temp = *it; if (m_lowPoint[temp] >= root) break; stack.push(m_nodeFromDFI[-m_dfi[temp]]); } }
// 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; } }
// Reduction reduced a set of leaves determined by their keys stored // in leafKeys. Integer redNumber is for debugging only. bool EmbedPQTree::Reduction(SListPure<PlanarLeafKey<IndInfo*>*> &leafKeys) { SListPure<PQLeafKey<edge, IndInfo*, bool>*> castLeafKeys; for (PlanarLeafKey<IndInfo*> *key : leafKeys) castLeafKeys.pushBack(static_cast<PQLeafKey<edge, IndInfo*, bool>*>(key)); return PQTree<edge, IndInfo*, bool>::Reduction(castLeafKeys); }
// 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 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 PlanarSPQRTree::setPosInEmbedding( NodeArray<SListPure<adjEntry> > &adjEdges, NodeArray<node> ¤tCopy, NodeArray<adjEntry> &lastAdj, SListPure<node> ¤t, const Skeleton &S, adjEntry adj) { node vT = S.treeNode(); adjEdges[vT].pushBack(adj); node vCopy = adj->theNode(); node vOrig = S.original(vCopy); if(currentCopy[vT] == nullptr) { currentCopy[vT] = vCopy; current.pushBack(vT); for (adjEntry adjVirt : vCopy->adjEdges) { edge eCopy = S.twinEdge(adjVirt->theEdge()); if (eCopy == nullptr) continue; if (adjVirt == adj) { lastAdj[vT] = adj; continue; } const Skeleton &STwin = skeleton(S.twinTreeNode(adjVirt->theEdge())); adjEntry adjCopy = (STwin.original(eCopy->source()) == vOrig) ? eCopy->adjSource() : eCopy->adjTarget(); setPosInEmbedding(adjEdges,currentCopy,lastAdj,current, STwin, adjCopy); } } else if (lastAdj[vT] != nullptr && lastAdj[vT] != adj) { adjEntry adjVirt = lastAdj[vT]; edge eCopy = S.twinEdge(adjVirt->theEdge()); const Skeleton &STwin = skeleton(S.twinTreeNode(adjVirt->theEdge())); adjEntry adjCopy = (STwin.original(eCopy->source()) == vOrig) ? eCopy->adjSource() : eCopy->adjTarget(); setPosInEmbedding(adjEdges,currentCopy,lastAdj,current, STwin, adjCopy); lastAdj[vT] = nullptr; } }
void EmbedPQTree::ReplaceRoot( SListPure<PlanarLeafKey<indInfo*>*> &leafKeys, SListPure<edge> &frontier, SListPure<node> &opposed, SListPure<node> &nonOpposed, node v) { SListPure<PQBasicKey<edge,indInfo*,bool>*> nodeFrontier; if (leafKeys.empty() && m_pertinentRoot == m_root) { front(m_pertinentRoot,nodeFrontier); m_pertinentRoot = 0; // check for this emptyAllPertinentNodes } else { if (m_pertinentRoot->status() == FULL) ReplaceFullRoot(leafKeys,nodeFrontier,v); else ReplacePartialRoot(leafKeys,nodeFrontier,v); } // Check the frontier and get the direction indicators. while (!nodeFrontier.empty()) { PQBasicKey<edge,indInfo*,bool>* entry = nodeFrontier.popFrontRet(); if (entry->userStructKey()) // is a regular leaf frontier.pushBack(entry->userStructKey()); else if (entry->userStructInfo()) { if (entry->userStructInfo()->changeDir) opposed.pushBack(entry->userStructInfo()->v); else nonOpposed.pushBack(entry->userStructInfo()->v); } } }
node PivotMDS::getRootedPath(const Graph& G) { node head = nullptr; NodeArray<bool> visited(G, false); SListPure<node> neighbors; // in every path there are two nodes with degree 1 and // each node has at most degree 2 for(node v : G.nodes) { int degree = 0; visited[v] = true; neighbors.pushBack(v); for(adjEntry adj : v->adjEntries) { node w = adj->twinNode(); if (!visited[w]) { neighbors.pushBack(w); visited[w]=true; ++degree; } } if (degree > 2) { neighbors.clear(); return nullptr; } if (degree == 1) { head = v; } for(node u : neighbors) { visited[u] = false; } neighbors.clear(); } return head; }
// 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); } }
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; }
void UpwardPlanarSubgraphSimple::dfsBuildSpanningTree( node v, SListPure<edge> &treeEdges, NodeArray<bool> &visited) { visited[v] = true; for(adjEntry adj : v->adjEntries) { edge e = adj->theEdge(); node w = e->target(); if(w == v) continue; if(!visited[w]) { treeEdges.pushBack(e); dfsBuildSpanningTree(w,treeEdges,visited); } } }
void UpwardPlanarSubgraphSimple::dfsBuildSpanningTree( node v, SListPure<edge> &treeEdges, NodeArray<bool> &visited) { visited[v] = true; edge e; forall_adj_edges(e,v) { node w = e->target(); if(w == v) continue; if(!visited[w]) { treeEdges.pushBack(e); dfsBuildSpanningTree(w,treeEdges,visited); } }
// 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); } }
//in ClusterGraph?? //is not yet recursive!!! node collapseCluster(ClusterGraph& CG, cluster c, Graph& G) { OGDF_ASSERT(c->cCount() == 0) ListIterator<node> its; SListPure<node> collaps; //we should check here if not empty node robinson = (*(c->nBegin())); for (its = c->nBegin(); its.valid(); its++) collaps.pushBack(*its); CG.collaps(collaps, G); if (c != CG.rootCluster()) CG.delCluster(c); return robinson; }
// 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; }
// 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); }
// // embed original graph according to embedding of skeletons // // The procedure also handles the case when some (real or virtual) // edges are reversed (used in upward-planarity algorithms) void PlanarSPQRTree::embed(Graph &G) { OGDF_ASSERT(&G == &originalGraph()); const Skeleton &S = skeleton(rootNode()); const Graph &M = S.getGraph(); for (node v : M.nodes) { node vOrig = S.original(v); SListPure<adjEntry> adjEdges; for (adjEntry adj : v->adjEdges) { edge e = adj->theEdge(); edge eOrig = S.realEdge(e); if (eOrig != nullptr) { adjEntry adjOrig = (vOrig == eOrig->source()) ? eOrig->adjSource() : eOrig->adjTarget(); OGDF_ASSERT(adjOrig->theNode() == S.original(v)); adjEdges.pushBack(adjOrig); } else { node wT = S.twinTreeNode(e); edge eTwin = S.twinEdge(e); expandVirtualEmbed(wT, (vOrig == skeleton(wT).original(eTwin->source())) ? eTwin->adjSource() : eTwin->adjTarget(), adjEdges); } } G.sort(vOrig,adjEdges); } edge e; forall_adj_edges(e,rootNode()) { node wT = e->target(); if (wT != rootNode()) createInnerVerticesEmbed(G, wT); }
// 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)); }
// The function front scans the frontier of nodePtr. It returns the keys // of the leaves found in the frontier of nodePtr in a SListPure. // These keys include keys of direction indicators detected in the frontier. // // CAREFUL: Funktion marks all full nodes for destruction. // Only to be used in connection with replaceRoot. // void EmbedPQTree::front( PQNode<edge,indInfo*,bool>* nodePtr, SListPure<PQBasicKey<edge,indInfo*,bool>*> &keys) { Stack<PQNode<edge,indInfo*,bool>*> S; S.push(nodePtr); while (!S.empty()) { PQNode<edge,indInfo*,bool> *checkNode = S.pop(); if (checkNode->type() == PQNodeRoot::leaf) keys.pushBack((PQBasicKey<edge,indInfo*,bool>*) checkNode->getKey()); else { PQNode<edge,indInfo*,bool>* firstSon = 0; if (checkNode->type() == PQNodeRoot::PNode) { firstSon = checkNode->referenceChild(); } else if (checkNode->type() == PQNodeRoot::QNode) { firstSon = checkNode->getEndmost(RIGHT); // By this, we make sure that we start on the left side // since the left endmost child will be on top of the stack } if (firstSon->status() == INDICATOR) { keys.pushBack((PQBasicKey<edge,indInfo*,bool>*) firstSon->getNodeInfo()); m_pertinentNodes->pushBack(firstSon); destroyNode(firstSon); } else S.push(firstSon); PQNode<edge,indInfo*,bool> *nextSon = firstSon->getNextSib(0); PQNode<edge,indInfo*,bool> *oldSib = firstSon; while (nextSon && nextSon != firstSon) { if (nextSon->status() == INDICATOR) { // Direction indicators point with their left sibling pointer // in the direction of their sequence. If an indicator is scanned // from the opposite direction, coming from its right sibling // the corresponding sequence must be reversed. if (oldSib == nextSon->getSib(LEFT)) //Direction changed nextSon->getNodeInfo()->userStructInfo()->changeDir = true; keys.pushBack((PQBasicKey<edge,indInfo*,bool>*) nextSon->getNodeInfo()); m_pertinentNodes->pushBack(nextSon); } else S.push(nextSon); PQNode<edge,indInfo*,bool> *holdSib = nextSon->getNextSib(oldSib); oldSib = nextSon; nextSon = holdSib; } } } }
void EmbedPQTree::ReplaceFullRoot( SListPure<PlanarLeafKey<IndInfo*>*> &leafKeys, SListPure<PQBasicKey<edge,IndInfo*,bool>*> &frontier, node v, bool addIndicator, PQNode<edge,IndInfo*,bool> *opposite) { EmbedIndicator *newInd = nullptr; front(m_pertinentRoot,frontier); if (addIndicator) { IndInfo *newInfo = new IndInfo(v); PQNodeKey<edge,IndInfo*,bool> *nodeInfoPtr = new PQNodeKey<edge,IndInfo*,bool>(newInfo); newInd = new EmbedIndicator(m_identificationNumber++, 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(nullptr,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,nullptr); newInd->changeSiblings(opposite,nullptr); newInd->putSibling(m_pertinentRoot,PQNodeRoot::SibDirection::Left); newInd->putSibling(opposite,PQNodeRoot::SibDirection::Right); } PQLeaf<edge,IndInfo*,bool> *leafPtr = new PQLeaf<edge,IndInfo*,bool>(m_identificationNumber++, PQNodeRoot::PQNodeStatus::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 = nullptr; // 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(nullptr, 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,nullptr); newInd->changeSiblings(opposite,nullptr); newInd->putSibling(m_pertinentRoot,PQNodeRoot::SibDirection::Left); newInd->putSibling(opposite,PQNodeRoot::SibDirection::Right); } PQInternalNode<edge,IndInfo*,bool> *nodePtr = nullptr; // dummy if ((m_pertinentRoot->type() == PQNodeRoot::PQNodeType::PNode) || (m_pertinentRoot->type() == PQNodeRoot::PQNodeType::QNode)) { nodePtr = (PQInternalNode<edge,IndInfo*,bool>*)m_pertinentRoot; nodePtr->type(PQNodeRoot::PQNodeType::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::PQNodeType::Leaf) { nodePtr = new PQInternalNode<edge,IndInfo*,bool>(m_identificationNumber++, PQNodeRoot::PQNodeType::PNode, PQNodeRoot::PQNodeStatus::Empty); exchangeNodes(m_pertinentRoot,nodePtr); m_pertinentRoot = nullptr; // check for this emptyAllPertinentNodes } SListPure<PQLeafKey<edge, IndInfo*, bool>*> castLeafKeys; for (PlanarLeafKey<IndInfo*> *key : leafKeys) castLeafKeys.pushBack(static_cast<PQLeafKey<edge, IndInfo*, bool>*>(key)); addNewLeavesToTree(nodePtr, castLeafKeys); } }
//-------------------------------------------------------------------- // 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; }
// 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); } } }
// extract external facepath in direction CCW and split the highest facepath // in highest xy-paths. marker marks the node, highMarker is used to check, // whether the node was visited before by the highest facepath traversal. // highMarker+1 identifies the nodes that are zNodes. void FindKuratowskis::extractExternalFacePath( SListPure<adjEntry>& externalFacePath, const ListPure<adjEntry>& highestFacePath, int marker, int highMarker) { int dir = CCW; // x traverses the external facepath node x = pBM->successorWithoutShortCircuit(k.R,dir); externalFacePath.pushBack(pBM->beforeShortCircuitEdge(k.R,CCW)); m_wasHere[k.R] = marker; while (x != k.R) { // set visited sign on nodes that are both on the highest and external facepath if (m_wasHere[x]>=highMarker) m_wasHere[x] = marker; externalFacePath.pushBack(pBM->beforeShortCircuitEdge(x,dir)); x = pBM->successorWithoutShortCircuit(x,dir); } dir = CCW; x = pBM->successorWithoutShortCircuit(k.R,dir); ListConstIterator<adjEntry> highIt = highestFacePath.begin(); OGDF_ASSERT(x == (*highIt)->theNode()); SListPure<adjEntry> XYPathList; SListPure<adjEntry> zList; WInfo info; adjEntry adj = pBM->beforeShortCircuitEdge(k.R,CCW); adjEntry temp; while (x != k.R) { // go along the highest face path until next visited sign OGDF_ASSERT(adj->theNode()==x); if (m_wasHere[x] == marker) { XYPathList.clear(); zList.clear(); info.w = NULL; info.minorType = 0; info.highestXYPath = NULL; info.zPath = NULL; info.pxAboveStopX = false; info.pyAboveStopY = false; info.externEStart = NULL; info.externEEnd = NULL; info.firstExternEAfterW = NULL; } // push in wNodes-list if (pBM->pertinent(x)) { info.w = x; k.wNodes.pushBack(info); } // compute next highestXYPath if (m_wasHere[x] == marker && m_wasHere[pBM->constSuccessorWithoutShortCircuit(x,dir)] != marker) { // traverse highFacePath to x while ((*highIt)->theNode() != x) ++highIt; OGDF_ASSERT(highIt.valid()); XYPathList.pushBack(adj); OGDF_ASSERT((*highIt.succ())->theNode() != pBM->constSuccessorWithoutShortCircuit(x,dir)); // traverse highFacePath to next marker do { ++highIt; if (!highIt.valid()) break; temp = *highIt; XYPathList.pushBack(temp); // check, if node is z-node and push one single z-node if (m_wasHere[temp->theNode()]==highMarker+1 && zList.empty()) zList.pushBack(temp); } while (m_wasHere[temp->theNode()] != marker); // save highestXY-Path OGDF_ASSERT(!XYPathList.empty()); k.highestXYPaths.pushBack(XYPathList); info.highestXYPath = &k.highestXYPaths.back(); // compute path from zNode to V and save it if (!zList.empty()) { OGDF_ASSERT(zList.size()==1); // just one zNode for now temp = zList.back(); do { do { temp = temp->cyclicSucc(); OGDF_ASSERT(m_dfi[temp->twinNode()]==m_dfi[k.R] || m_dfi[temp->twinNode()]>=m_dfi[k.RReal]); } while (m_edgeType[temp->theEdge()]==EDGE_BACK_DELETED); temp = temp->twin(); zList.pushBack(temp); } while (temp->theNode() != k.R); k.zPaths.pushBack(zList); info.zPath = &k.zPaths.back(); } } // go on adj = pBM->beforeShortCircuitEdge(x,dir); x = pBM->successorWithoutShortCircuit(x,dir); } }
//--------------------------------------------------------- // 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 }
void EmbedPQTree::ReplacePartialRoot( SListPure<PlanarLeafKey<indInfo*>*> &leafKeys, SListPure<PQBasicKey<edge,indInfo*,bool>*> &frontier, node v) { m_pertinentRoot->childCount(m_pertinentRoot->childCount() + 1 - fullChildren(m_pertinentRoot)->size()); PQNode<edge,indInfo*,bool> *predNode = 0; // dummy PQNode<edge,indInfo*,bool> *beginSequence = 0; // marks begin consecuitve seqeunce PQNode<edge,indInfo*,bool> *endSequence = 0; // marks end consecutive sequence PQNode<edge,indInfo*,bool> *beginInd = 0; // initially, marks direct sibling indicator // next to beginSequence not contained // in consectuive sequence // Get beginning and end of sequence. while (fullChildren(m_pertinentRoot)->size()) { PQNode<edge,indInfo*,bool> *currentNode = fullChildren(m_pertinentRoot)->popFrontRet(); if (!clientSibLeft(currentNode) || clientSibLeft(currentNode)->status() == EMPTY) { if (!beginSequence) { beginSequence = currentNode; predNode = clientSibLeft(currentNode); beginInd =PQTree<edge,indInfo*,bool>::clientSibLeft(currentNode); } else endSequence = currentNode; } else if (!clientSibRight(currentNode) || clientSibRight(currentNode)->status() == EMPTY ) { if (!beginSequence) { beginSequence = currentNode; predNode = clientSibRight(currentNode); beginInd =PQTree<edge,indInfo*,bool>::clientSibRight(currentNode); } else endSequence = currentNode; } } SListPure<PQBasicKey<edge,indInfo*,bool>*> partialFrontier; // Now scan the sequence of full nodes. Remove all of them but the last. // Call ReplaceFullRoot on the last one. // For every full node get its frontier. Scan intermediate indicators. PQNode<edge,indInfo*,bool> *currentNode = beginSequence; while (currentNode != endSequence) { PQNode<edge,indInfo*,bool>* nextNode = clientNextSib(currentNode,predNode); front(currentNode,partialFrontier); frontier.conc(partialFrontier); PQNode<edge,indInfo*,bool>* currentInd = PQTree<edge,indInfo*,bool>:: clientNextSib(currentNode,beginInd); // Scan for intermediate direction indicators. while (currentInd != nextNode) { PQNode<edge,indInfo*,bool> *nextInd = PQTree<edge,indInfo*,bool>:: clientNextSib(currentInd,currentNode); if (currentNode == currentInd->getSib(RIGHT)) //Direction changed currentInd->getNodeInfo()->userStructInfo()->changeDir = true; frontier.pushBack((PQBasicKey<edge,indInfo*,bool>*) currentInd->getNodeInfo()); removeChildFromSiblings(currentInd); m_pertinentNodes->pushBack(currentInd); currentInd = nextInd; } removeChildFromSiblings(currentNode); currentNode = nextNode; } currentNode->parent(m_pertinentRoot); m_pertinentRoot = currentNode; ReplaceFullRoot(leafKeys,partialFrontier,v,true,beginInd); frontier.conc(partialFrontier); }
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); } }