1 /** \file
2 * \brief implementation of the class FindKuratowskis
3 *
4 * \author Jens Schmidt
5 *
6 * \par License:
7 * This file is part of the Open Graph Drawing Framework (OGDF).
8 *
9 * \par
10 * Copyright (C)<br>
11 * See README.md in the OGDF root directory for details.
12 *
13 * \par
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * Version 2 or 3 as published by the Free Software Foundation;
17 * see the file LICENSE.txt included in the packaging of this file
18 * for details.
19 *
20 * \par
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * \par
27 * You should have received a copy of the GNU General Public
28 * License along with this program; if not, see
29 * http://www.gnu.org/copyleft/gpl.html
30 */
31
32
33 #include <ogdf/planarity/boyer_myrvold/FindKuratowskis.h>
34 #include <ogdf/basic/simple_graph_alg.h>
35
36
37 namespace ogdf {
38
39
40 // copy pointer of class Kuratowski
copyPointer(const KuratowskiStructure & orig,SListPure<WInfo> & list)41 void KuratowskiStructure::copyPointer(const KuratowskiStructure& orig, SListPure<WInfo>& list) {
42 auto itHighOrig = orig.highestXYPaths.begin();
43 auto itZOrig = orig.zPaths.begin();
44 auto itExternStartOrig = orig.externE.begin();
45 auto itExternEndOrig = orig.externE.begin();
46 auto itZ = zPaths.begin();
47 auto itHigh = highestXYPaths.begin();
48 auto itExternStart = externE.begin();
49 auto itExternEnd = externE.begin();
50
51 for (WInfo &info : list) {
52 if (info.highestXYPath!=nullptr) {
53 // go to referenced object
54 while (info.highestXYPath != &(*itHighOrig)) {
55 ++itHigh;
56 ++itHighOrig;
57 }
58 OGDF_ASSERT(itHigh.valid());
59 OGDF_ASSERT(itHighOrig.valid());
60 info.highestXYPath=&(*itHigh);
61 }
62 if (info.zPath!=nullptr) {
63 // go to referenced object
64 while (info.zPath != &(*itZOrig)) {
65 ++itZ;
66 ++itZOrig;
67 }
68 OGDF_ASSERT(itZ.valid());
69 OGDF_ASSERT(itZOrig.valid());
70 info.zPath=&(*itZ);
71 }
72 if (info.externEStart.valid()) {
73 // go to referenced object
74 while ((*info.externEStart).theNode != (*itExternStartOrig).theNode) {
75 ++itExternStartOrig;
76 ++itExternStart;
77 }
78 OGDF_ASSERT(itExternStartOrig.valid());
79 OGDF_ASSERT(itExternStart.valid());
80 info.externEStart = itExternStart;
81 }
82 if (info.externEEnd.valid()) {
83 // go to referenced object
84 while ((*info.externEEnd).theNode != (*itExternEndOrig).theNode) {
85 ++itExternEndOrig;
86 ++itExternEnd;
87 }
88 OGDF_ASSERT(itExternEndOrig.valid());
89 OGDF_ASSERT(itExternEnd.valid());
90 info.externEEnd = itExternEnd;
91 }
92 }
93 }
94
95 // copy class Kuratowski
copy(const KuratowskiStructure & orig)96 void KuratowskiStructure::copy(const KuratowskiStructure& orig) {
97 V = orig.V;
98 V_DFI = orig.V_DFI;
99 R = orig.R;
100 RReal = orig.RReal;
101 stopX = orig.stopX;
102 stopY = orig.stopY;
103
104 wNodes = orig.wNodes;
105 highestFacePath = orig.highestFacePath;
106 highestXYPaths = orig.highestXYPaths;
107 externalFacePath = orig.externalFacePath;
108 externalSubgraph = orig.externalSubgraph;
109 pertinentSubgraph = orig.pertinentSubgraph;
110 zPaths = orig.zPaths;
111 externE = orig.externE;
112 stopXStartnodes = orig.stopXStartnodes;
113 stopYStartnodes = orig.stopYStartnodes;
114 stopXEndnodes = orig.stopXEndnodes;
115 stopYEndnodes = orig.stopYEndnodes;
116
117 // copy pointer
118 copyPointer(orig,wNodes);
119 }
120
121
122 // clears members
clear()123 void KuratowskiStructure::clear()
124 {
125 V=R=RReal=stopX=stopY=nullptr;
126 V_DFI = 0;
127 wNodes.clear();
128 highestFacePath.clear();
129 highestXYPaths.clear();
130 externalFacePath.clear();
131 externalSubgraph.clear();
132 pertinentSubgraph.clear();
133 zPaths.clear();
134 externE.clear();
135 stopXStartnodes.clear();
136 stopYStartnodes.clear();
137 stopXEndnodes.clear();
138 stopYEndnodes.clear();
139 }
140
141 // class FindKuratowski
FindKuratowskis(BoyerMyrvoldPlanar * bm)142 FindKuratowskis::FindKuratowskis(BoyerMyrvoldPlanar* bm) :
143 pBM(bm),
144 m_g(bm->m_g),
145 m_embeddingGrade(bm->m_embeddingGrade),
146
147 m_bundles(bm->m_bundles),
148
149 // initialize Members of BoyerMyrvoldPlanar
150 m_realVertex(bm->m_realVertex),
151 m_dfi(bm->m_dfi),
152 m_nodeFromDFI(bm->m_nodeFromDFI),
153 m_link(bm->m_link),
154 m_adjParent(bm->m_adjParent),
155 m_leastAncestor(bm->m_leastAncestor),
156 m_edgeType(bm->m_edgeType),
157 m_lowPoint(bm->m_lowPoint),
158 m_highestSubtreeDFI(bm->m_highestSubtreeDFI),
159 m_separatedDFSChildList(bm->m_separatedDFSChildList),
160 m_pointsToRoot(bm->m_pointsToRoot),
161 m_numUnembeddedBackedgesInBicomp(bm->m_numUnembeddedBackedgesInBicomp),
162 m_backedgeFlags(bm->m_backedgeFlags),
163 m_pertinentRoots(bm->m_pertinentRoots)
164 {
165 OGDF_ASSERT(bm != nullptr);
166 m_nodeMarker = 0;
167 }
168
169 // finds root node of the bicomp containing the stopping node stopX
findRoot(node stopX) const170 node FindKuratowskis::findRoot(node stopX) const {
171 int dir = BoyerMyrvoldPlanar::DirectionCCW;
172 while (m_realVertex[stopX]==nullptr)
173 stopX = pBM->successorWithoutShortCircuit(stopX,dir);
174 return stopX;
175 }
176
177 // extracts highest face path (contains all highest xy-paths)
extractHighestFacePath(ArrayBuffer<adjEntry> & highestFacePath,int marker)178 void FindKuratowskis::extractHighestFacePath(
179 ArrayBuffer<adjEntry>& highestFacePath,
180 int marker) {
181 adjEntry adj = pBM->beforeShortCircuitEdge(k.R,BoyerMyrvoldPlanar::DirectionCCW);
182 adjEntry end = pBM->beforeShortCircuitEdge(k.R,BoyerMyrvoldPlanar::DirectionCW);
183 node target;
184 while (adj != end->twin()) {
185 node x = adj->theNode();
186
187 if (m_wasHere[x] >= marker) {
188 // node is already visited on facepath: pop until duplicate node found
189 OGDF_ASSERT(!highestFacePath.empty());
190 while (highestFacePath.top()->theNode() != x) highestFacePath.pop();
191 // sign cut-vertex with marker+1
192 m_wasHere[x] = marker+1;
193 } else {
194 highestFacePath.push(adj);
195 // sign visited nodes with marker
196 m_wasHere[x] = marker;
197 }
198
199 do {
200 adj = adj->cyclicSucc();
201 target = adj->twinNode();
202 if (target == k.R) m_wasHere[x] = marker+1;
203 } while (adj != end &&
204 (m_edgeType[adj->theEdge()] == BoyerMyrvoldEdgeType::BackDeleted ||
205 m_dfi[target] <= m_dfi[k.R]));
206 adj = adj->twin();
207 }
208 }
209
210 // extract external facepath in direction CCW and split the highest facepath
211 // in highest xy-paths. marker marks the node, highMarker is used to check,
212 // whether the node was visited before by the highest facepath traversal.
213 // highMarker+1 identifies the nodes that are zNodes.
extractExternalFacePath(SListPure<adjEntry> & externalFacePath,const ArrayBuffer<adjEntry> & highestFacePath,int marker,int highMarker)214 void FindKuratowskis::extractExternalFacePath(
215 SListPure<adjEntry>& externalFacePath,
216 const ArrayBuffer<adjEntry>& highestFacePath,
217 int marker,
218 int highMarker)
219 {
220 int dir = BoyerMyrvoldPlanar::DirectionCCW;
221 // x traverses the external facepath
222 node x = pBM->successorWithoutShortCircuit(k.R,dir);
223 externalFacePath.pushBack(pBM->beforeShortCircuitEdge(k.R,BoyerMyrvoldPlanar::DirectionCCW));
224 m_wasHere[k.R] = marker;
225 while (x != k.R) {
226 // set visited sign on nodes that are both on the highest and external facepath
227 if (m_wasHere[x]>=highMarker) m_wasHere[x] = marker;
228 externalFacePath.pushBack(pBM->beforeShortCircuitEdge(x,dir));
229 x = pBM->successorWithoutShortCircuit(x,dir);
230 }
231
232 dir = BoyerMyrvoldPlanar::DirectionCCW;
233 x = pBM->successorWithoutShortCircuit(k.R,dir);
234 auto highIt = highestFacePath.begin();
235 OGDF_ASSERT(x == (*highIt)->theNode());
236 ArrayBuffer<adjEntry> XYPathList;
237 ArrayBuffer<adjEntry> zList;
238 WInfo info;
239 adjEntry adj = pBM->beforeShortCircuitEdge(k.R,BoyerMyrvoldPlanar::DirectionCCW);
240 adjEntry temp;
241 while (x != k.R) {
242 // go along the highest face path until next visited sign
243 OGDF_ASSERT(adj->theNode()==x);
244 if (m_wasHere[x] == marker) {
245 XYPathList.clear();
246 zList.clear();
247 info.w = nullptr;
248 info.minorType = 0;
249 info.highestXYPath = nullptr;
250 info.zPath = nullptr;
251 info.pxAboveStopX = false;
252 info.pyAboveStopY = false;
253 info.externEStart = nullptr;
254 info.externEEnd = nullptr;
255 info.firstExternEAfterW = nullptr;
256 }
257
258 // push in wNodes-list
259 if (pBM->pertinent(x)) {
260 info.w = x;
261 k.wNodes.pushBack(info);
262 }
263
264 // compute next highestXYPath
265 if (m_wasHere[x] == marker &&
266 m_wasHere[pBM->constSuccessorWithoutShortCircuit(x,dir)] != marker) {
267 // traverse highFacePath to x
268 while ((*highIt)->theNode() != x) ++highIt;
269 OGDF_ASSERT(highIt != highestFacePath.end());
270 XYPathList.push(adj);
271 OGDF_ASSERT((*(highIt + 1))->theNode() != pBM->constSuccessorWithoutShortCircuit(x, dir));
272
273 // traverse highFacePath to next marker
274 do {
275 ++highIt;
276 if (highIt == highestFacePath.end()) break;
277 temp = *highIt;
278 XYPathList.push(temp);
279 // check, if node is z-node and push one single z-node
280 if (m_wasHere[temp->theNode()]==highMarker+1 && zList.empty())
281 zList.push(temp);
282 } while (m_wasHere[temp->theNode()] != marker);
283
284 // save highestXY-Path
285 OGDF_ASSERT(!XYPathList.empty());
286 k.highestXYPaths.pushBack(XYPathList);
287 info.highestXYPath = &k.highestXYPaths.back();
288
289 // compute path from zNode to V and save it
290 if (!zList.empty()) {
291 OGDF_ASSERT(zList.size()==1); // just one zNode for now
292 temp = zList.top();
293 do {
294 do {
295 temp = temp->cyclicSucc();
296 OGDF_ASSERT(m_dfi[temp->twinNode()]==m_dfi[k.R] ||
297 m_dfi[temp->twinNode()]>=m_dfi[k.RReal]);
298 } while (m_edgeType[temp->theEdge()]==BoyerMyrvoldEdgeType::BackDeleted);
299 temp = temp->twin();
300 zList.push(temp);
301 } while (temp->theNode() != k.R);
302 k.zPaths.pushBack(zList);
303 info.zPath = &k.zPaths.back();
304 }
305 }
306
307 // go on
308 adj = pBM->beforeShortCircuitEdge(x,dir);
309 x = pBM->successorWithoutShortCircuit(x,dir);
310 }
311 }
312
313 // separate pertinent nodes in the lists of possible different minor-types
splitInMinorTypes(const SListPure<adjEntry> & externalFacePath,int marker)314 void FindKuratowskis::splitInMinorTypes(
315 const SListPure<adjEntry>& externalFacePath,
316 int marker)
317 {
318 // mark nodes, which are before stopX or behind stopY in CCW-traversal and add
319 // all extern nodes strictly between stopX and stopY to list
320 // externE for minor E (pertinent nodes are considered because of the
321 // position of z left or right of w)
322 SListIterator<WInfo> it = k.wNodes.begin();
323 bool between = false;
324 SListPure<WInfo*> infoList;
325 ExternE externEdummy;
326 // compute list of externE nodes
327 for (auto adj : externalFacePath) {
328 node x = adj->theNode();
329 if (x==k.stopX || x==k.stopY) {
330 between = !between;
331 } else {
332 if (!between) {
333 m_wasHere[x]=marker;
334 } else {
335 if (pBM->externallyActive(x,k.V_DFI)) {
336 externEdummy.theNode = x;
337
338 // check minor type B and save extern linkage
339 if (it.valid() && (*it).w==x &&
340 !m_pertinentRoots[x].empty() &&
341 m_lowPoint[m_nodeFromDFI[-m_dfi[m_pertinentRoots[x].back()]]]
342 < k.V_DFI) {
343 WInfo& info(*it);
344
345 // checking minor type B
346 info.minorType |= WInfo::MinorType::B;
347 // mark extern node for later extraction
348 externEdummy.startnodes.pushBack(0);
349 // create externE-list
350 k.externE.pushBack(externEdummy);
351 // save extern linkage
352 info.externEStart = k.externE.backIterator();
353 info.externEEnd = k.externE.backIterator();
354 } else {
355 // create externE-list
356 externEdummy.startnodes.clear();
357 k.externE.pushBack(externEdummy);
358 }
359
360 // save for each wNode the first externally active successor
361 // on the external face
362 for (auto info : infoList) {
363 info->firstExternEAfterW = x;
364 }
365 infoList.clear();
366 }
367
368 // get appropriate WInfo
369 if (it.valid() && (*it).w==x) {
370 infoList.pushBack(&(*it));
371 ++it;
372 }
373 }
374 }
375 }
376
377 // divide wNodes in different minor types
378 // avoids multiple computation of the externE range
379 SListConstIterator<adjEntry> itExtern = externalFacePath.begin();
380 SListIterator<ExternE> itExternE = k.externE.begin();
381 WInfo* oldInfo = nullptr;
382 for (WInfo& info : k.wNodes) {
383 // checking minor type A
384 if (k.RReal!=k.V) info.minorType |= WInfo::MinorType::A;
385
386 // if a XYPath exists
387 if (info.highestXYPath!=nullptr) {
388 if (m_wasHere[(*info.highestXYPath)[0]->theNode()] == marker)
389 info.pxAboveStopX = true;
390 if (m_wasHere[info.highestXYPath->top()->theNode()] == marker)
391 info.pyAboveStopY = true;
392
393 // checking minor type C
394 if (info.pxAboveStopX || info.pyAboveStopY)
395 info.minorType |= WInfo::MinorType::C;
396
397 // checking minor type D
398 if (info.zPath!=nullptr) info.minorType |= WInfo::MinorType::D;
399
400 // checking minor type E
401 if (!k.externE.empty()) {
402 node t;
403
404 // compute valid range of externE-nodes in linear time
405 if (oldInfo!=nullptr && info.highestXYPath==oldInfo->highestXYPath) {
406 // found the same highestXYPath as before
407 info.externEStart = oldInfo->externEStart;
408 info.externEEnd = oldInfo->externEEnd;
409 if (oldInfo->minorType & WInfo::MinorType::E) info.minorType |= WInfo::MinorType::E;
410 } else {
411 // compute range of a new highestXYPath
412 node px;
413 if (info.pxAboveStopX) {
414 px = k.stopX;
415 } else {
416 px = (*info.highestXYPath)[0]->theNode();
417 }
418 node py;
419 if (info.pyAboveStopY) {
420 py = k.stopY;
421 } else {
422 py = info.highestXYPath->top()->theNode();
423 }
424 while ((*itExtern)->theNode() != px) ++itExtern;
425 t = (*(++itExtern))->theNode();
426 node start = nullptr;
427 node end = nullptr;
428 while (t != py) {
429 if (pBM->externallyActive(t,k.V_DFI)) {
430 if (start==nullptr) start = t;
431 end = t;
432 }
433 t = (*(++itExtern))->theNode();
434 }
435 if (start != nullptr) {
436 while ((*itExternE).theNode != start) ++itExternE;
437 info.externEStart = itExternE;
438 // mark node to extract external subgraph later
439 (*itExternE).startnodes.pushBack(0);
440 node temp = start;
441 while (temp != end) {
442 temp = (*++itExternE).theNode;
443 // mark node to extract external subgraph later
444 (*itExternE).startnodes.pushBack(0);
445 }
446 info.externEEnd = itExternE;
447 info.minorType |= WInfo::MinorType::E;
448 }
449 oldInfo = &info;
450 }
451 }
452 }
453
454 #if 0
455 // use this to find special kuratowski-structures
456 if ((info.minorType & (WInfo::A|WInfo::B|WInfo::C|WInfo::D|WInfo::E)) ==
457 (WInfo::A|WInfo::B|WInfo::C|WInfo::D|WInfo::E)) {
458 char t; std::cin >> t;
459 }
460 #endif
461 }
462
463 // extract the externalSubgraph of all saved externally active nodes
464 // exclude the already extracted minor b-types
465 #ifdef OGDF_DEBUG
466 int visited = m_nodeMarker+1;
467 #endif
468 for (ExternE& externE : k.externE) {
469 if (externE.startnodes.empty()) continue;
470
471 externE.startnodes.clear();
472 if (m_bundles) {
473 OGDF_ASSERT(m_wasHere[externE.theNode] < visited);
474 extractExternalSubgraphBundles(externE.theNode, k.V_DFI, k.externalSubgraph, ++m_nodeMarker);
475 } else {
476 extractExternalSubgraph(externE.theNode, k.V_DFI, externE.startnodes, externE.endnodes);
477
478 // Add externE.startnodes.size() many dummy elements.
479 // It is done this way because size() takes linear time and
480 // a range-based for-loop needs an unused variable.
481 SListPure<edge> dummy;
482 for (auto itInt = externE.startnodes.begin(); itInt.valid(); ++itInt) {
483 externE.externalPaths.pushBack(dummy);
484 }
485 }
486 }
487 }
488
489 // extracts and adds external subgraph from stopnode to ancestors of the node with dfi root
490 // to edgelist, nodeMarker is used as a visited flag. returns the endnode with lowest dfi.
extractExternalSubgraph(const node stop,int root,SListPure<int> & externalStartnodes,SListPure<node> & externalEndnodes)491 void FindKuratowskis::extractExternalSubgraph(
492 const node stop,
493 int root,
494 SListPure<int>& externalStartnodes,
495 SListPure<node>& externalEndnodes)
496 {
497 if (m_leastAncestor[stop] < root) {
498 externalStartnodes.pushBack(m_dfi[stop]);
499 externalEndnodes.pushBack(m_nodeFromDFI[m_leastAncestor[stop]]);
500 }
501
502 for (node temp : m_separatedDFSChildList[stop]) {
503 // descent to external active child bicomps of stopnode
504 int lowpoint = m_lowPoint[temp];
505 if (lowpoint >= root) break;
506
507 externalStartnodes.pushBack(m_dfi[temp]);
508 externalEndnodes.pushBack(m_nodeFromDFI[lowpoint]);
509 }
510 }
511
512 // extract and add external subgraph from stopnode to ancestors of the node with dfi root
513 // to edgelist, nodeMarker is used as a visited flag. returns the endnode with lowest dfi.
extractExternalSubgraphBundles(const node stop,int root,SListPure<edge> & externalSubgraph,int nodeMarker)514 void FindKuratowskis::extractExternalSubgraphBundles(
515 const node stop,
516 int root,
517 SListPure<edge>& externalSubgraph,
518 int nodeMarker)
519 {
520 #ifdef OGDF_DEBUG
521 for (node v : m_g.nodes)
522 OGDF_ASSERT(m_wasHere[v] != nodeMarker);
523 #endif
524
525 ArrayBuffer<node> stack; // stack for dfs-traversal
526 stack.push(stop);
527 while (!stack.empty()) {
528 node v = stack.popRet();
529 if (m_wasHere[v] == nodeMarker) continue;
530 // mark visited nodes
531 m_wasHere[v] = nodeMarker;
532
533 // search for unvisited nodes and add them to stack
534 for (adjEntry adj : v->adjEntries) {
535 node temp = adj->twinNode();
536 if (m_edgeType[adj->theEdge()] == BoyerMyrvoldEdgeType::BackDeleted) continue;
537
538 // go along backedges to ancestor (ignore virtual nodes)
539 if (m_dfi[temp] < root && m_dfi[temp] > 0) {
540 OGDF_ASSERT(m_edgeType[adj->theEdge()] == BoyerMyrvoldEdgeType::Back);
541 externalSubgraph.pushBack(adj->theEdge());
542 } else if (v != stop && m_dfi[temp] >= m_dfi[v]) {
543 // set flag and push unvisited nodes
544 OGDF_ASSERT(m_edgeType[adj->theEdge()] == BoyerMyrvoldEdgeType::Back ||
545 m_edgeType[adj->theEdge()] == BoyerMyrvoldEdgeType::Dfs ||
546 m_edgeType[adj->theEdge()] == BoyerMyrvoldEdgeType::BackDeleted);
547 externalSubgraph.pushBack(adj->theEdge());
548 if (m_wasHere[temp] != nodeMarker) stack.push(temp);
549 }
550 }
551
552 // descent to external active child bicomps
553 for (node temp : m_separatedDFSChildList[v]) {
554 if (m_lowPoint[temp] >= root)
555 break;
556 stack.push(m_nodeFromDFI[-m_dfi[temp]]);
557 }
558 }
559 }
560
561
562 // extract pertinent paths from all w-nodes to k.V to edgelist
extractPertinentSubgraph(SListPure<WInfo> & W_All)563 void FindKuratowskis::extractPertinentSubgraph(
564 SListPure<WInfo>& W_All)
565 {
566 SListPure<edge> path;
567 int minDFI = -m_dfi[k.R];
568 int maxDFI = m_highestSubtreeDFI[m_nodeFromDFI[minDFI]];
569
570 // create links from pertinent nodes to WInfo
571 for (WInfo &info : W_All) {
572 m_getWInfo[info.w] = &info;
573 }
574
575 // add all pertinent paths to WInfo
576 for (adjEntry adj : k.V->adjEntries) {
577 if (m_edgeType[adj->theEdge()] == BoyerMyrvoldEdgeType::BackDeleted) continue;
578 int targetDFI = m_dfi[adj->twinNode()];
579 if (targetDFI >= minDFI && targetDFI <= maxDFI) {
580 // target node is in subtree of a pertinent node
581
582 // delete last edge and backedgeFlags
583 node target = adj->twinNode();
584 edge e = adj->theEdge();
585 path.pushFront(e);
586 OGDF_ASSERT(!m_backedgeFlags[target].empty());
587 m_backedgeFlags[target].clear();
588 m_edgeType[e] = BoyerMyrvoldEdgeType::BackDeleted;
589 // delete backedge-counter on virtual root node
590 --m_numUnembeddedBackedgesInBicomp[m_pointsToRoot[e]];
591 OGDF_ASSERT(m_numUnembeddedBackedgesInBicomp[m_pointsToRoot[e]] >= 0);
592
593 // go up along the DFS-path
594 while (m_getWInfo[target] == nullptr) {
595 path.pushFront(m_adjParent[target]->theEdge());
596 target = m_adjParent[target]->theNode();
597 if (m_realVertex[target] != nullptr) {
598 target = m_realVertex[target];
599 m_pertinentRoots[target].clear();
600 }
601 }
602
603 // save path
604 m_getWInfo[target]->pertinentPaths.pushBack(path);
605 path.clear();
606 }
607 }
608
609 // delete links from pertinent nodes to WInfo
610 for (const WInfo &info : W_All) {
611 m_getWInfo[info.w] = nullptr;
612 }
613 }
614
615
616 // extract and add pertinent subgraph from all w-nodes to v to edgelist
extractPertinentSubgraphBundles(const SListPure<WInfo> & W_All,const node V,SListPure<edge> & pertinentSubgraph,int nodeMarker)617 void FindKuratowskis::extractPertinentSubgraphBundles(
618 const SListPure<WInfo>& W_All,
619 const node V,
620 SListPure<edge>& pertinentSubgraph,
621 int nodeMarker)
622 {
623 #ifdef OGDF_DEBUG
624 for (node w : m_g.nodes)
625 OGDF_ASSERT(m_wasHere[w] != nodeMarker);
626 #endif
627
628 ArrayBuffer<node> stack; // stack for dfs-traversal
629 // for all w-nodes
630 for (const WInfo &info : W_All) {
631 node currentWNode = info.w;
632 stack.push(currentWNode);
633
634 // until stack is empty, do dfs-traversal in bicomps and descent to
635 // pertinent child bicomps
636 while (!stack.empty()) {
637 node w = stack.popRet();
638 if (m_wasHere[w] == nodeMarker) continue;
639 // mark visited nodes
640 m_wasHere[w] = nodeMarker;
641
642 // search for unvisited nodes and add them to stack
643 for (adjEntry adj : w->adjEntries) {
644 edge e = adj->theEdge();
645 if (m_edgeType[e] == BoyerMyrvoldEdgeType::BackDeleted) continue;
646 node x = adj->twinNode();
647
648 // go along pertinent backedges to V (ignore virtual nodes)
649 if (x == V && m_edgeType[e] != BoyerMyrvoldEdgeType::BackDeleted) {
650 OGDF_ASSERT(m_edgeType[e] == BoyerMyrvoldEdgeType::Back);
651 // delete edge and delete backedgeFlags
652 m_edgeType[e] = BoyerMyrvoldEdgeType::BackDeleted;
653 m_backedgeFlags[w].clear();
654 // delete backedge-counter on virtual root node
655 --m_numUnembeddedBackedgesInBicomp[m_pointsToRoot[e]];
656 OGDF_ASSERT(m_numUnembeddedBackedgesInBicomp[m_pointsToRoot[e]] >= 0);
657 pertinentSubgraph.pushBack(e);
658 } else if (w != currentWNode && m_dfi[x] >= m_dfi[w]) {
659 OGDF_ASSERT(m_edgeType[adj->theEdge()] == BoyerMyrvoldEdgeType::Dfs ||
660 m_edgeType[adj->theEdge()] == BoyerMyrvoldEdgeType::Back ||
661 m_edgeType[adj->theEdge()] == BoyerMyrvoldEdgeType::BackDeleted);
662 // set flag and push unvisited nodes
663 pertinentSubgraph.pushBack(e);
664 if (m_wasHere[x] != nodeMarker) stack.push(x);
665 }
666 }
667
668 // descent to pertinent child bicomps
669 for (node v : m_pertinentRoots[w]) {
670 stack.push(v);
671 }
672 // delete all pertinentRoots-lists, since there are no pertinent backedges any more
673 m_pertinentRoots[w].clear();
674 }
675 }
676 }
677
678
679 // add Kuratowski structure on current node V
addKuratowskiStructure(const node currentNode,const node root,const node stopx,const node stopy)680 void FindKuratowskis::addKuratowskiStructure(
681 const node currentNode,
682 const node root,
683 const node stopx,
684 const node stopy)
685 {
686 OGDF_ASSERT(currentNode != nullptr);
687 OGDF_ASSERT(root != nullptr);
688 OGDF_ASSERT(stopx != nullptr);
689 OGDF_ASSERT(stopy != nullptr);
690 OGDF_ASSERT(stopx != stopy);
691 OGDF_ASSERT(currentNode != stopx);
692 OGDF_ASSERT(currentNode != stopy);
693 OGDF_ASSERT(m_dfi[root] < 0);
694 OGDF_ASSERT(!pBM->pertinent(stopx));
695 OGDF_ASSERT(pBM->externallyActive(stopx,m_dfi[currentNode]));
696 OGDF_ASSERT(!pBM->pertinent(stopy));
697 OGDF_ASSERT(pBM->externallyActive(stopy,m_dfi[currentNode]));
698 OGDF_ASSERT(findRoot(stopx)==root); // check root
699 OGDF_ASSERT(pBM->wNodesExist(root,stopx,stopy));
700 OGDF_ASSERT(isSimpleUndirected(m_g)); // Graph has to be simple
701 OGDF_ASSERT(m_embeddingGrade > BoyerMyrvoldPlanar::EmbeddingGrade::doNotFind);
702 // check, if we have found enough kuratowski structures
703 OGDF_ASSERT(m_embeddingGrade <= 0 || allKuratowskis.size() < m_embeddingGrade);
704
705 // init NodeArrays in first invocation
706 if (!m_wasHere.valid()) {
707 if (!m_bundles) {
708 OGDF_ASSERT(!m_getWInfo.valid());
709 OGDF_ASSERT(m_getWInfo.graphOf() == nullptr);
710 m_getWInfo.init(m_g,nullptr);
711 }
712 OGDF_ASSERT(m_wasHere.graphOf() == nullptr);
713 m_wasHere.init(m_g,0);
714 }
715
716 // delete old KuratowskiStruture and initialize new structure
717 k.clear();
718 k.V = currentNode;
719 k.V_DFI = m_dfi[currentNode];
720 k.stopX = stopx;
721 k.stopY = stopy;
722 k.R = root;
723 k.RReal = m_realVertex[k.R];
724
725 // flip bicomp with root R with or without reversed flipping. changes the embedding
726 // process completely.
727 pBM->flipBicomp(-m_dfi[k.R],++m_nodeMarker,m_wasHere,false,true);
728 // pBM->flipBicomp(-m_dfi[k.R],++m_nodeMarker,m_wasHere,false,false);
729
730 // extract highest facepath (contains all highest xy-paths)
731 extractHighestFacePath(k.highestFacePath,++m_nodeMarker);
732 ++m_nodeMarker;
733
734 // extract external facepath in direction CCW and split the highest facepath in
735 // highest xy-paths
736 ++m_nodeMarker;
737 extractExternalFacePath(k.externalFacePath,k.highestFacePath,m_nodeMarker,
738 m_nodeMarker-2);
739
740 // extract external subgraph from stopX and stopY to ancestors of R
741 if (m_bundles) {
742 extractExternalSubgraphBundles(k.stopX,k.V_DFI,k.externalSubgraph,++m_nodeMarker);
743 } else {
744 extractExternalSubgraph(k.stopX,k.V_DFI,k.stopXStartnodes,k.stopXEndnodes);
745 }
746
747 if (m_bundles) {
748 extractExternalSubgraphBundles(k.stopY,k.V_DFI,k.externalSubgraph,++m_nodeMarker);
749 } else {
750 extractExternalSubgraph(k.stopY,k.V_DFI,k.stopYStartnodes,k.stopYEndnodes);
751 }
752
753 // pass pertinent nodes in the lists of possible different minor-types
754 splitInMinorTypes(k.externalFacePath,++m_nodeMarker);
755
756 // extract pertinent subgraphs from all w-nodes to k.V
757 if (m_bundles) {
758 extractPertinentSubgraphBundles(k.wNodes,k.V,k.pertinentSubgraph,++m_nodeMarker);
759 } else {
760 extractPertinentSubgraph(k.wNodes/*,k.V*/);
761 }
762
763 // add Kuratowski to KuratowskisOnNode
764 allKuratowskis.pushBack(k);
765
766 // reverse flipping
767 #if 0
768 pBM->flipBicomp(-m_dfi[k.R],++m_nodeMarker,m_wasHere,false,false);
769 #endif
770
771 OGDF_ASSERT(m_bundles || k.pertinentSubgraph.empty());
772 }
773
774
775 }
776