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; }
void PlanarSPQRTree::adoptEmbedding() { OGDF_ASSERT_IF(dlExtendedChecking, originalGraph().representsCombEmbedding()); // ordered list of adjacency entries (for one original node) in all // skeletons (where this node occurs) NodeArray<SListPure<adjEntry> > adjEdges(tree()); // copy in skeleton of current original node NodeArray<node> currentCopy(tree(),nullptr); NodeArray<adjEntry> lastAdj(tree(),nullptr); SListPure<node> current; // currently processed nodes for (node vOrig : originalGraph().nodes) { for(adjEntry adjOrig : vOrig->adjEdges) { edge eOrig = adjOrig->theEdge(); const Skeleton &S = skeletonOfReal(eOrig); edge eCopy = copyOfReal(eOrig); adjEntry adjCopy = (S.original(eCopy->source()) == vOrig) ? eCopy->adjSource() : eCopy->adjTarget(); setPosInEmbedding(adjEdges,currentCopy,lastAdj,current,S,adjCopy); } for(node vT : current) { skeleton(vT).getGraph().sort(currentCopy[vT],adjEdges[vT]); adjEdges[vT].clear(); currentCopy[vT] = nullptr; } current.clear(); } }
// 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); } }
// start DFS-traversal void BoyerMyrvoldInit::computeDFS() { // compute random edge costs EdgeArray<int> costs; EdgeComparer comp; if(m_randomness > 0 && m_edgeCosts != nullptr) { costs.init(m_g); int minCost = std::numeric_limits<int>::max(); int maxCost = std::numeric_limits<int>::min(); for(edge e : m_g.edges) { minCost = min(minCost, (*m_edgeCosts)[e]); maxCost = min(maxCost, (*m_edgeCosts)[e]); } std::uniform_real_distribution<> urd(-1, 1); for(edge e : m_g.edges) { costs[e] = minCost + (int)((1 - m_randomness) * ((*m_edgeCosts)[e] - minCost) + m_randomness * (maxCost - minCost) * urd(m_rand)); } comp.setCosts(&costs); } else if(m_edgeCosts != nullptr) { comp.setCosts(m_edgeCosts); } StackPure<adjEntry> stack; int nextDFI = 1; const int numberOfNodes = m_g.numberOfNodes(); SListPure<adjEntry> adjList; SListPure<node> list; m_g.allNodes(list); // get random dfs-tree, if wanted if (m_randomness > 0) { list.permute(); } for (node v : list) { if (v->degree() == 0) { m_dfi[v] = nextDFI; m_leastAncestor[v] = nextDFI; m_nodeFromDFI[nextDFI] = v; ++nextDFI; } else { adjList.clear(); m_g.adjEntries(v, adjList); adjList.quicksort(comp); m_g.sort(v, adjList); stack.push(v->firstAdj()); } } while (nextDFI <= numberOfNodes) { OGDF_ASSERT(!stack.empty()); adjEntry prnt = stack.pop(); node v = prnt->theNode(); // check, if node v was visited before. if (m_dfi[v] != 0) continue; // parentNode=nullptr on first node on connected component node parentNode = prnt->twinNode(); if (m_dfi[parentNode] == 0) parentNode = nullptr; // if not, mark node as visited and initialize NodeArrays m_dfi[v] = nextDFI; m_leastAncestor[v] = nextDFI; m_nodeFromDFI[nextDFI] = v; ++nextDFI; // push all adjacent nodes onto stack for(adjEntry adj : v->adjEdges) { edge e = adj->theEdge(); if (adj == prnt && parentNode != nullptr) continue; // check for self-loops and dfs- and dfs-parallel edges node w = adj->twinNode(); if (m_dfi[w] == 0) { m_edgeType[e] = EDGE_DFS; m_adjParent[w] = adj; m_link[CW][w] = adj; m_link[CCW][w] = adj; // found new dfs-edge: preorder stack.push(adj->twin()); } else if (w == v) { // found self-loop m_edgeType[e] = EDGE_SELFLOOP; } else { // node w already has been visited and is an dfs-ancestor of v OGDF_ASSERT(m_dfi[w] < m_dfi[v]); if (w == parentNode) { // found parallel edge of dfs-parent-edge m_edgeType[e] = EDGE_DFS_PARALLEL; } else { // found backedge m_edgeType[e] = EDGE_BACK; // set least Ancestor if (m_dfi[w] < m_leastAncestor[v]) m_leastAncestor[v] = m_dfi[w]; } } } } }