Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

Loading...
Searching...
No Matches
NonPlanarCore.h
Go to the documentation of this file.
1
33#pragma once
34
35#include <ogdf/basic/Queue.h>
40
41namespace ogdf {
42
44
64template<typename TCost = int>
66 template<typename T>
67 friend class GlueMap;
68
69public:
74 struct CutEdge {
75 const edge e;
76 const bool dir;
77
78 CutEdge(edge paramEdge, bool directed) : e(paramEdge), dir(directed) {};
79 };
80
91 explicit NonPlanarCore(const Graph& G, bool nonPlanarityGuaranteed = false);
92
98 NonPlanarCore(const Graph& G, const EdgeArray<TCost>& weight,
99 bool nonPlanarityGuaranteed = false);
100
108 NonPlanarCore(const Graph& G, const EdgeArray<TCost>& weight,
110
112 const Graph& core() const { return m_graph; }
113
115 const Graph& originalGraph() const { return *m_pOriginal; }
116
118 node original(node v) const { return m_orig[v]; }
119
123 if (isVirtual(e)) {
125 for (edge eInCop : origEdgesOfThisSTComponent.graphOf()->edges) {
126 if (origEdgesOfThisSTComponent[eInCop] != nullptr) {
128 }
129 }
130 } else {
131 res.pushBack(realEdge(e));
132 }
133 return res;
134 }
135
137 bool isVirtual(edge e) const { return m_real[e] == nullptr; }
138
140 edge realEdge(edge e) const { return m_real[e]; }
141
146 const EdgeArray<TCost>& cost() const { return m_cost; }
147
152 node tNode(edge e) const { return m_tNode[e]; }
153
158 node sNode(edge e) const { return m_sNode[e]; }
159
163 EdgeArray<edge>* mapE(edge e) const { return m_mapE[e]; }
164
169 TCost cost(edge e) const { return m_cost[e]; }
170
172 const List<CutEdge>& mincut(edge e) const { return m_mincut[e]; }
173
174 // destructor
175 virtual ~NonPlanarCore();
176
178
185
186protected:
190
200
219
229
235
244
253
261
267
275 void getMincut(edge e, List<edge>& cut);
276
286
294
297
300
306
312
315
318
321
324
327
330
333
336
339
342};
343
347template<typename TCost>
425
426template<typename TCost>
428 : m_pOriginal(&G)
429 , m_orig(m_graph)
430 , m_real(m_graph, nullptr)
431 , m_mincut(m_graph)
432 , m_cost(m_graph)
433 , m_T(G)
434 , m_mapV(m_graph, nullptr)
435 , m_mapE(m_graph, nullptr)
436 , m_underlyingGraphs(m_graph, nullptr)
437 , m_sNode(m_graph)
438 , m_tNode(m_graph) {
441}
442
443template<typename TCost>
446 : m_pOriginal(&G)
447 , m_orig(m_graph)
448 , m_real(m_graph, nullptr)
449 , m_mincut(m_graph)
450 , m_cost(m_graph)
451 , m_T(G)
452 , m_mapV(m_graph, nullptr)
453 , m_mapE(m_graph, nullptr)
454 , m_underlyingGraphs(m_graph, nullptr)
455 , m_sNode(m_graph)
456 , m_tNode(m_graph) {
458}
459
460template<typename TCost>
463 : m_pOriginal(&G)
464 , m_orig(m_graph)
465 , m_real(m_graph, nullptr)
466 , m_mincut(m_graph)
467 , m_cost(m_graph)
468 , m_T(G)
469 , m_mapV(m_graph, nullptr)
470 , m_mapE(m_graph, nullptr)
471 , m_underlyingGraphs(m_graph, nullptr)
472 , m_sNode(m_graph)
473 , m_tNode(m_graph) {
476}
477
478template<typename TCost>
480 for (auto pointer : m_mapE) {
481 delete pointer;
482 }
483 for (auto pointer : m_mapV) {
484 delete pointer;
485 }
486 for (auto pointer : m_underlyingGraphs) {
487 delete pointer;
488 }
489}
490
491template<typename TCost>
494 if (!nonPlanarityGuaranteed && isPlanar(G)) {
495 return;
496 }
499
500 // mark tree nodes in the core
501 NodeArray<bool> mark;
502 markCore(mark);
503
504 NodeArray<node> map(G, nullptr);
505 NodeArray<node> mapAux(G, nullptr);
506 const Graph& tree = m_T.tree();
507
508 for (node v : tree.nodes) {
509 if (!mark[v]) {
510 continue;
511 }
512
513 Skeleton& S = m_T.skeleton(v);
514
515 for (edge e : S.getGraph().edges) {
516 node src = S.original(e->source());
517 node tgt = S.original(e->target());
518
519 if (tgt == src) {
520 continue;
521 }
522
523 if (map[src] == nullptr) {
524 m_orig[map[src] = m_graph.newNode()] = S.original(e->source());
525 }
526
527 if (map[tgt] == nullptr) {
528 m_orig[map[tgt] = m_graph.newNode()] = S.original(e->target());
529 }
530
531 if (S.isVirtual(e)) {
532 node w = S.twinTreeNode(e);
533
534 if (!mark[w]) {
535 // new virtual edge in core graph
536 edge lastCreatedEdge = m_graph.newEdge(map[src], map[tgt]);
537 m_real[lastCreatedEdge] = nullptr;
538 traversingPath(S, e, m_mincut[lastCreatedEdge], mapAux, lastCreatedEdge, weight,
540 }
541 } else {
542 // new real edge in core graph
543 edge lastCreatedEdge = m_graph.newEdge(map[src], map[tgt]);
544 m_real[lastCreatedEdge] = S.realEdge(e);
545 traversingPath(S, e, m_mincut[lastCreatedEdge], mapAux, lastCreatedEdge, weight,
547 }
548 }
549 }
550
551 if (weight != nullptr) {
552 for (edge e : m_graph.edges) {
553 TCost cost(0);
554 for (auto cutEdge : m_mincut[e]) {
555 cost += (*weight)[cutEdge.e];
556 }
557 m_cost[e] = cost;
558 }
559 } else {
560 for (edge e : m_graph.edges) {
561 m_cost[e] = m_mincut[e].size();
562 }
563 }
564
565 List<node> allNodes;
566 m_graph.allNodes(allNodes);
567
568 // The while loop is used to eliminate multiedges from the core. We're pruning P-Nodes.
571 getAllMultiedges(winningMultiEdges, losingMultiEdges);
572 while (!winningMultiEdges.empty() && !losingMultiEdges.empty()) {
574 edge losingMultiEdge = losingMultiEdges.popFrontRet();
575#ifdef OGDF_DEBUG
576 int sizeOfWinCut = m_mincut[winningMultiEdge].size();
577 int sizeOfLosCut = m_mincut[losingMultiEdge].size();
578#endif
579
581 glueMincuts(winningMultiEdge, losingMultiEdge);
582
584 delete m_underlyingGraphs[losingMultiEdge];
585 delete m_mapV[losingMultiEdge];
586 delete m_mapE[losingMultiEdge];
587 m_real[winningMultiEdge] = nullptr;
588 m_real[losingMultiEdge] = nullptr;
589 m_graph.delEdge(losingMultiEdge);
590 }
591 // The for loop is used to eliminate deg 2 nodes from the core. We're pruning S-Nodes.
592 for (node v : allNodes) {
593 if (v->degree() != 2) {
594 continue;
595 }
596 edge outEdge = v->firstAdj()->theEdge();
597 edge inEdge = v->lastAdj()->theEdge();
598
599 if (m_cost[inEdge] > m_cost[outEdge]) {
600 std::swap(inEdge, outEdge);
601 }
602 // We join the embeddings of the underlying embeddings/graphs of both edges
603 // so that outEdge gets integrated into inEdge
604 glue(inEdge, outEdge);
605
606 m_real[inEdge] = nullptr;
607 m_real[outEdge] = nullptr;
608
609 adjEntry adjSource = inEdge->adjSource()->cyclicSucc();
610 adjEntry adjTarget = (outEdge->target() == v ? outEdge->adjSource()->cyclicSucc()
611 : outEdge->adjTarget()->cyclicSucc());
612 if (inEdge->target() != v) {
613 adjSource = adjTarget;
614 adjTarget = inEdge->adjTarget()->cyclicSucc();
615 }
616 m_graph.move(inEdge, adjSource, ogdf::Direction::before, adjTarget, ogdf::Direction::before);
617 delete m_underlyingGraphs[outEdge];
618 delete m_mapV[outEdge];
619 delete m_mapE[outEdge];
620 m_graph.delNode(v);
621 }
622
623
625 OGDF_ASSERT(!isPlanar(m_graph));
626 }
627}
628
629template<typename TCost>
631 const Graph& tree = m_T.tree();
632
633 // We mark every tree node that belongs to the core
634 mark.init(tree, true); // start with all nodes and unmark planar leaves
635 NodeArray<int> degree(tree);
636
638
639 for (node v : tree.nodes) {
640 degree[v] = v->degree();
641 if (degree[v] <= 1) { // also append deg-0 node (T has only one node)
642 Q.append(v);
643 }
644 }
645
646 while (!Q.empty()) {
647 node v = Q.pop();
648
649 // if v has a planar skeleton
650 if (m_T.typeOf(v) != SPQRTree::NodeType::RNode || isPlanar(m_T.skeleton(v).getGraph())) {
651 mark[v] = false; // unmark this leaf
652
653 node w = nullptr;
654 for (adjEntry adj : v->adjEntries) {
655 node x = adj->twinNode();
656 if (mark[x]) {
657 w = x;
658 break;
659 }
660 }
661
662 if (w != nullptr) {
663 --degree[w];
664 if (degree[w] == 1) {
665 Q.append(w);
666 }
667 }
668 }
669 }
670}
671
678
679template<typename TCost>
683 List<CutEdge>& currPath = path;
684
685 // Build the graph representing the planar st-component
686 Graph* h_pointer = new Graph();
687 Graph& H = *h_pointer;
688
693 SListPure<node> nodes;
695
696 if (Sv.isVirtual(eS)) {
698 Q.append(QueueEntry(Sv.treeNode(), Sv.twinTreeNode(eS)));
699
700 while (!Q.empty()) {
701 QueueEntry x = Q.pop();
702 node parent = x.m_parent;
704
705 const Skeleton& S = m_T.skeleton(current);
706 for (edge e : S.getGraph().edges) {
707 if (S.isVirtual(e)) {
708 continue;
709 }
710
711 node src = S.original(e->source());
712 node tgt = S.original(e->target());
713
714 if (mapV[src] == nullptr) {
715 nodes.pushBack(src);
716 mapV[src] = H.newNode();
717 mapV_src[mapV[src]] = src;
718 }
719 if (mapV[tgt] == nullptr) {
720 nodes.pushBack(tgt);
721 mapV[tgt] = H.newNode();
722 mapV_src[mapV[tgt]] = tgt;
723 }
724
725 edge e_new = H.newEdge(mapV[src], mapV[tgt]);
726 mapE_src[e_new] = S.realEdge(e);
727 OGDF_ASSERT(mapE_src[e_new]->source() != nullptr);
728 }
729
730 for (adjEntry adj : current->adjEntries) {
731 node w = adj->twinNode();
732 if (w != parent) {
733 Q.append(QueueEntry(current, w));
734 }
735 }
736 }
737 } else {
738 nodes.pushBack(Sv.original(eS->source()));
739 nodes.pushBack(Sv.original(eS->target()));
740 mapV[Sv.original(eS->source())] = H.newNode();
741 mapV_src[mapV[Sv.original(eS->source())]] = Sv.original(eS->source());
742 mapV[Sv.original(eS->target())] = H.newNode();
743 mapV_src[mapV[Sv.original(eS->target())]] = Sv.original(eS->target());
744 mapE_src[H.newEdge(mapV[Sv.original(eS->source())], mapV[Sv.original(eS->target())])] =
745 Sv.realEdge(eS);
746 }
747 // add st-edge
748 edge e_st = H.newEdge(mapV[Sv.original(eS->source())], mapV[Sv.original(eS->target())]);
749 m_sNode[coreEdge] = mapV[Sv.original(eS->source())];
750 m_tNode[coreEdge] = mapV[Sv.original(eS->target())];
751
752 // Compute planar embedding of H
753#ifdef OGDF_DEBUG
754 bool ok =
755#endif
756 planarEmbed(H);
757 OGDF_ASSERT(ok);
759
760 // we rearange the adj Lists of s and t, so that adj(e_st) is the first adj
763 e_st->source()->allAdjEntries(adjListFront);
764 if (adjListFront.front() != e_st->adjSource()) {
765 adjListFront.split(adjListFront.search(e_st->adjSource()), adjListFront, adjListBack);
766 adjListFront.concFront(adjListBack);
767 H.sort(e_st->source(), adjListFront);
768 }
769
770 e_st->target()->allAdjEntries(adjListFront);
771 if (adjListFront.front() != e_st->adjTarget()) {
772 adjListFront.split(adjListFront.search(e_st->adjTarget()), adjListFront, adjListBack,
774 adjListFront.concFront(adjListBack);
775 H.sort(e_st->target(), adjListFront);
776 }
777
778 if (Sv.isVirtual(eS)) {
779 List<edge> edgeList;
780 if (weight_src != nullptr) {
781 EdgeArray<TCost> weight(H);
782 for (edge e : H.edges) {
783 if (e != e_st) {
784 weight[e] = (*weight_src)[mapE_src[e]];
785 }
786 }
787 minSTCutModule->call(H, weight, e_st->source(), e_st->target(), edgeList, e_st);
788 } else {
789 minSTCutModule->call(H, e_st->source(), e_st->target(), edgeList, e_st);
790 }
791 auto it = edgeList.begin();
792 for (; it != edgeList.end(); it++) {
793 currPath.pushBack(CutEdge(mapE_src[*it], minSTCutModule->direction(*it)));
794 }
795 } else {
796 OGDF_ASSERT(Sv.realEdge(eS) != nullptr);
797 currPath.pushFront(CutEdge(Sv.realEdge(eS), true));
798 }
799 H.delEdge(e_st);
800
801 OGDF_ASSERT(m_underlyingGraphs[coreEdge] == nullptr);
802 m_underlyingGraphs[coreEdge] = h_pointer;
803 OGDF_ASSERT(m_mapE[coreEdge] == nullptr);
804 m_mapE[coreEdge] = mapE_src_pointer;
805 OGDF_ASSERT(m_mapV[coreEdge] == nullptr);
806 m_mapV[coreEdge] = mapV_src_pointer;
807#ifdef OGDF_DEBUG
808 for (node v : H.nodes) {
809 OGDF_ASSERT(mapV_src[v] != nullptr);
810 }
811 for (edge e : H.edges) {
812 OGDF_ASSERT(mapE_src[e] != nullptr);
813 }
814#endif
815
816 for (node v : nodes) {
817 mapV[v] = nullptr;
818 }
819}
820
821template<typename TCost>
823 winningEdges.clear();
824 losingEdges.clear();
825 SListPure<edge> edges;
826 EdgeArray<int> minIndex(m_graph), maxIndex(m_graph);
828
829 SListConstIterator<edge> it = edges.begin();
830 edge ePrev = *it, e;
831 for (it = ++it; it.valid(); ++it, ePrev = e) {
832 e = *it;
833 if (minIndex[ePrev] == minIndex[e] && maxIndex[ePrev] == maxIndex[e]) {
834 winningEdges.pushFront(ePrev);
835 losingEdges.pushFront(e);
836 }
837 }
838}
839
840template<typename TCost>
842 GlueMap<TCost> map(eWinner, eLoser, *this);
843
844 // true iff this glueing is about a PNode (so a glueing at two common nodes)
845 bool thisIsAboutAPNode = false;
846 if (eLoser->isParallelUndirected(eWinner)) {
847 thisIsAboutAPNode = true;
848 }
849
850 // find the s- and t-nodes in their skeleton for both of the edges
851 node sWinner = m_sNode[eWinner];
852 node tWinner = m_tNode[eWinner];
853 node sLoser = m_sNode[eLoser];
854 node tLoser = m_tNode[eLoser];
855
856 bool sameDirection {!eWinner->isInvertedDirected(eLoser)};
857
858 // we get a list of all nodes of the loser graph
861
862#ifdef OGDF_DEBUG
863 bool ok = true;
864#endif
865
866 // for both s and t of eLoser we check if it's either the s or the t node of eWinner
867 // if one of it is, we delete it from the list of nodes, that are to be added
868 // otherwise it stays in 'allNodesButSt' to be added later
869 if (eLoser->source() == eWinner->source() || eLoser->source() == eWinner->target()) {
870#ifdef OGDF_DEBUG
871 ok =
872#endif
873 allNodesButSt.removeFirst(sLoser);
874 OGDF_ASSERT(ok);
875 if (eLoser->source() == eWinner->source()) {
877 } else {
879 }
880 OGDF_ASSERT(!allNodesButSt.search(sLoser).valid());
881 }
882 if (eLoser->target() == eWinner->source() || eLoser->target() == eWinner->target()) {
883#ifdef OGDF_DEBUG
884 ok =
885#endif
886 allNodesButSt.removeFirst(tLoser);
887 OGDF_ASSERT(ok);
888 if (eLoser->target() == eWinner->source()) {
890 } else {
892 }
893 OGDF_ASSERT(!allNodesButSt.search(tLoser).valid());
894 }
895
896
897 // insert the remaining nodes of the loser graph into the winner graph
898 for (node v : allNodesButSt) {
900 }
901
902 // insert all edges of the loser graph into the the winner graph
903 for (edge e : map.getLoserGraph().edges) {
905 }
906
907 // reorder the adjEntries of every node of the loser graph in the winner graph,
908 // to match the embedding in the loser graph
909 List<node> allNodes = allNodesButSt;
910 allNodes.pushBack(sLoser);
911 allNodes.pushBack(tLoser);
912 for (node v : allNodes) {
913 map.reorder(v, sameDirection, (tLoser == v && thisIsAboutAPNode));
914 }
915 if (!thisIsAboutAPNode) {
916 if (eWinner->source() == eLoser->source()) {
918 }
919 if (eWinner->target() == eLoser->source()) {
921 }
922 if (eWinner->source() == eLoser->target()) {
924 }
925 if (eWinner->target() == eLoser->target()) {
927 }
928 }
929}
930
931template<typename TCost>
933 bool pCisPlanar) {
934#ifdef OGDF_DEBUG
936 copyCore.removePseudoCrossings();
937 OGDF_ASSERT(copyCore.numberOfNodes() == planarCore.numberOfNodes());
938#endif
939 m_endGraph = &planarGraph;
940 m_planarCore = &planarCore;
941 OGDF_ASSERT(!pCisPlanar || m_planarCore->genus() == 0);
942 m_endGraph->clear();
943 m_endGraph->createEmpty(*m_pOriginal);
944 List<node> allNodes;
945 m_pOriginal->allNodes(allNodes);
946 EdgeArray<edge> eCopy(*m_pOriginal, nullptr);
947 m_endGraph->initByNodes(allNodes, eCopy);
948
949#ifdef OGDF_DEBUG
950 for (node v : m_endGraph->nodes) {
951 List<adjEntry> adjEntries;
952 v->allAdjEntries(adjEntries);
953 OGDF_ASSERT(v->degree() == adjEntries.size());
954 }
955#endif
956
957 // For every node of the core we rearrange the adjacency order of the corresponding endGraph node
958 // according to the planarized core.
959 for (node v : m_planarCore->nodes) {
960 if (m_planarCore->isDummy(v)) {
961 continue;
962 }
964 v->allAdjEntries(pcOrder);
965 List<adjEntry> newOrder;
966 node coreNode = m_planarCore->original(v);
967 OGDF_ASSERT(coreNode != nullptr);
968 for (adjEntry adjPC : v->adjEntries) {
969 edge coreEdge = m_planarCore->original(adjPC->theEdge());
970 EdgeArray<edge>& mapE = *m_mapE[coreEdge];
971 NodeArray<node>& mapV = *m_mapV[coreEdge];
972 node stNode = (mapV[m_sNode[coreEdge]] == original(coreNode) ? m_sNode[coreEdge]
973 : m_tNode[coreEdge]);
974 // find the node of emb which represents the same node v represents
975 for (adjEntry adjEmb : stNode->adjEntries) {
976 if (adjEmb->theEdge()->source() == adjEmb->theNode()) {
977 newOrder.pushBack(m_endGraph->copy(mapE[adjEmb->theEdge()])->adjSource());
978 } else {
979 newOrder.pushBack(m_endGraph->copy(mapE[adjEmb->theEdge()])->adjTarget());
980 }
981 }
982 }
983 m_endGraph->sort(m_endGraph->copy(original(coreNode)), newOrder);
984 }
985 if (!pCisPlanar) {
986 for (edge e : m_graph.edges) {
987 importEmbedding(e);
988 }
989 return;
990 } else {
992 for (edge e : m_graph.edges) {
993 // for every edge from the core we ensure, that the embedding of the subgraph it describes
994 // is the same in both the original and the end graph
995 importEmbedding(e);
996 // reverse all cut edges, which are not the same direction as e
997 normalizeCutEdgeDirection(e);
998 // to ensure the right order of the inserted crossings, we insert dummy nodes
999 // to split the edge in sections, each of which only has one crossing
1000 splitEdgeIntoSections(e, splitdummies);
1001 }
1002
1003 // now we can start and insert the crossings of the planar core into the end graph.
1004 // a node represents a crossing if it's a dummy
1005 for (node v : m_planarCore->nodes) {
1006 if (m_planarCore->isDummy(v)) {
1007 inflateCrossing(v);
1008 }
1009 }
1010 OGDF_ASSERT(m_endGraph->genus() == 0);
1011
1012 removeSplitdummies(splitdummies);
1013 for (edge e : m_graph.edges) {
1014 normalizeCutEdgeDirection(e);
1015 }
1016 }
1017}
1018
1019template<typename TCost>
1021 for (auto cutE : m_mincut[coreEdge]) {
1022 if (!cutE.dir) {
1023 for (edge e : m_endGraph->chain(cutE.e)) {
1024 m_endGraph->reverseEdge(e);
1025 }
1026 }
1027 }
1028}
1029
1030template<typename TCost>
1032 for (node v : splitdummies) {
1033 edge eIn = v->firstAdj()->theEdge();
1034 edge eOut = v->lastAdj()->theEdge();
1035 if (eIn->target() == v) {
1036 m_endGraph->unsplit(eIn, eOut);
1037 } else {
1038 m_endGraph->unsplit(eOut, eIn);
1039 }
1040 }
1041}
1042
1043template<typename TCost>
1045 List<edge> chain = m_planarCore->chain(e);
1046 int chainSize = chain.size();
1047 while (chainSize > 2) {
1048 for (CutEdge cutEdge : mincut(e)) {
1049 splitdummies.pushBack(m_endGraph->split(m_endGraph->copy(cutEdge.e))->source());
1050 }
1051 chainSize--;
1052 }
1053#ifdef OGDF_DEBUG
1054 for (CutEdge cutEdge : mincut(e)) {
1055 if (chain.size() < 3) {
1056 OGDF_ASSERT(m_endGraph->chain(cutEdge.e).size() == 1);
1057 } else {
1058 OGDF_ASSERT(m_endGraph->chain(cutEdge.e).size() == chain.size() - 1);
1059 }
1060 OGDF_ASSERT(m_endGraph->original(m_endGraph->chain(cutEdge.e).front()) == cutEdge.e);
1061 }
1062#endif
1063}
1064
1065template<typename TCost>
1067 const Graph& embG = *m_underlyingGraphs[e];
1068 // a map from the nodes of the emb to those in the end graph
1069 const EdgeArray<edge>& mapE_toOrig = *m_mapE[e];
1070 // bc the edges of the end graph are split for the crossing insertion,
1071 // a map of the emb might have more than one edge in the endgraph, we just
1072 // map the AdjEntries of both source and target of each edge of emb
1073 // to AdjEntries in the end graph
1074 const NodeArray<node>& mapV_toOrig = *m_mapV[e];
1076 for (auto it = mapE_toOrig.begin(); it != mapE_toOrig.end(); it++) {
1077 OGDF_ASSERT(it.key() != nullptr);
1078 OGDF_ASSERT((*it) != nullptr);
1079 OGDF_ASSERT((*it)->graphOf() == m_pOriginal);
1080 mapA_toFinal[it.key()->adjSource()] = m_endGraph->chain(*it).front()->adjSource();
1081 mapA_toFinal[it.key()->adjTarget()] = m_endGraph->chain(*it).back()->adjTarget();
1082 }
1083 node s(m_sNode[e]), t(m_tNode[e]);
1085 embG.allNodes(nodesOfEmb);
1086 // for every node of emb we order the adjEntries of the corresponding node
1087 // in the end graph, so that both match
1088 for (node v : nodesOfEmb) {
1089 if (v == s || v == t) {
1090 continue;
1091 }
1093 for (adjEntry adj = v->firstAdj(); adj; adj = adj->succ()) {
1094 rightAdjOrder.pushBack(mapA_toFinal[adj]);
1095 }
1096 m_endGraph->sort(m_endGraph->copy(mapV_toOrig[v]), rightAdjOrder);
1097 }
1098}
1099
1100template<typename TCost>
1102 // we want e1 and e2 to be these two edges
1103 // ^
1104 // |
1105 // e2-->v--->
1106 // ^
1107 // |
1108 // e1
1109 edge e1 = v->firstAdj()->theEdge();
1110 while (e1->target() != v) {
1111 e1 = e1->adjSource()->succ()->theEdge();
1112 }
1113 edge e2 = e1->adjTarget()->succ()->theEdge();
1114 while (e2->target() != v) {
1115 e2 = e2->adjSource()->cyclicSucc()->theEdge();
1116 }
1117 if (e1 == e2->adjTarget()->cyclicSucc()->theEdge()) {
1118 edge help = e1;
1119 e1 = e2;
1120 e2 = help;
1121 }
1122 OGDF_ASSERT(e2 == e1->adjTarget()->cyclicSucc()->theEdge());
1124 getMincut(e1, e1cut);
1126 getMincut(e2, e2cut);
1127 OGDF_ASSERT(e1 != e2);
1128 OGDF_ASSERT(e1cut.size() > 0);
1129 OGDF_ASSERT(e2cut.size() > 0);
1130 // the actual crossing insertion
1131 // for (auto it1 = e1cut.begin(); it1.valid(); it1++)
1132 for (int i = 0; i < e1cut.size(); i++) {
1133 auto it1 = e1cut.get(i);
1135 for (int j = 0; j < e2cut.size(); j++) {
1136 auto it2 = e2cut.get(j);
1137 edge crossedEdge = *it2;
1138 m_endGraph->insertCrossing(*it1, crossedEdge, true);
1140 e2cut.insertAfter(crossedEdge, it2);
1141 e2cut.del(it2);
1142 }
1144 e1cut.insertAfter(crossingEdge, it1);
1145 e1cut.del(it1);
1146 }
1147}
1148
1149template<typename TCost>
1151 OGDF_ASSERT(e->graphOf() == m_planarCore);
1152
1153 cut.clear();
1154 // chain is a list of the edges of the planar core, that represent e
1155 List<edge> chain = m_planarCore->chain(m_planarCore->original(e));
1156 // this is the main part of this function:
1157 // as we know, the cut edges are split by splitdummies to partition the edge,
1158 // such that every crossing on the edge has its own section to be inserted into (denoted by pos)
1159 // cut_pre stores the first section for every cut edge
1160 for (CutEdge eCut : mincut(m_planarCore->original(e))) {
1161 OGDF_ASSERT(m_endGraph->chain(eCut.e).size() + 1 >= chain.size());
1162 // while iterating we have to differentiate between already inserted crossings and splitdummies
1163 // we can do that, by only counting the deg 2 nodes we pass while iterating through the chain of the cut edge
1164 auto it = m_endGraph->chain(eCut.e).begin();
1165 for (int i = 0; i < chain.pos(chain.search(e)); i++) {
1166 it++;
1167 while ((*it)->source()->degree() == 4) {
1168 it++;
1169 OGDF_ASSERT(it.valid());
1170 }
1171 }
1172 cut.pushBack(*(it));
1173 }
1174 // cut is the result of this function
1175}
1176
1177template<typename TCost>
1179#ifdef OGDF_DEBUG
1180 if (eWinner->adjSource()->theNode() == eLoser->adjSource()->theNode()) {
1181 OGDF_ASSERT(eWinner->adjSource()->theNode() == eLoser->adjSource()->theNode());
1182 OGDF_ASSERT(eWinner->adjTarget()->theNode() == eLoser->adjTarget()->theNode());
1183 } else {
1184 OGDF_ASSERT(eWinner->adjSource()->theNode() == eLoser->adjTarget()->theNode());
1185 OGDF_ASSERT(eWinner->adjTarget()->theNode() == eLoser->adjSource()->theNode());
1186 }
1187#endif
1188 List<CutEdge> wincut = m_mincut[eWinner];
1189
1190 List<CutEdge> losecut = m_mincut[eLoser];
1191
1192 if (eWinner->source() == eLoser->target()) {
1194 for (auto cutEit = losecut.begin(); cutEit != losecut.end(); cutEit++) {
1195 newLosecut.pushBack(CutEdge((*cutEit).e, !(*cutEit).dir));
1196 }
1198 }
1199
1200 wincut.conc(losecut);
1201 m_mincut[eWinner] = wincut;
1202 m_cost[eWinner] += m_cost[eLoser];
1203}
1204
1205template<typename TCost>
1239
1240template<typename TCost>
1242 edge newEdge = m_gWinner->newEdge(m_mapV_l2w[loser->source()], m_mapV_l2w[loser->target()]);
1243 m_mapE_l2w[loser] = newEdge;
1244 (*m_mapEwinner)[newEdge] = (*m_mapEloser)[loser];
1245}
1246
1247template<typename TCost>
1249 m_mapV_l2w[loser] = winner;
1250 (*m_mapVwinner)[winner] = (*m_mapVloser)[loser];
1251}
1252
1253template<typename TCost>
1255 node newNode = m_gWinner->newNode();
1256 m_mapV_l2w[loser] = newNode;
1257 (*m_mapVwinner)[newNode] = (*m_mapVloser)[loser];
1258}
1259
1260template<typename TCost>
1261void GlueMap<TCost>::reorder(node vLoser, bool sameDirection, bool isTNodeOfPNode) {
1262 node vWinner = m_mapV_l2w[vLoser];
1265 vWinner->allAdjEntries(wrongAdjOrder);
1266 OGDF_ASSERT(wrongAdjOrder.size() == vWinner->degree());
1267
1268 OGDF_ASSERT(vLoser->degree() <= vWinner->degree());
1269 // for every adjEntry of v in the "right" graph (the embedding which we want to get into the "wrong" graph)
1270 // we search for the corresponding adjEntry in the list of adjEntries of the "wrong" v
1271 for (adjEntry adj : vLoser->adjEntries) {
1272 OGDF_ASSERT(m_mapE_l2w[adj->theEdge()] != nullptr);
1273 edge edgeInWinner = m_mapE_l2w[adj->theEdge()];
1274 adjEntry adj_in = (adj->theEdge()->adjSource() == adj ? edgeInWinner->adjSource()
1275 : edgeInWinner->adjTarget());
1276 rightAdjOrder.pushBack(adj_in);
1277 }
1279 vWinner->allAdjEntries(adjOrder);
1280 OGDF_ASSERT(vLoser->degree() <= adjOrder.size());
1281 if (!sameDirection) {
1282 rightAdjOrder.reverse();
1283 }
1284 if (adjOrder.size() == rightAdjOrder.size()) {
1286 } else {
1288 adjOrder.split(adjOrder.get(adjOrder.size() - rightAdjOrder.size()), adjOrder, helpList);
1289 if (isTNodeOfPNode) {
1290 adjOrder.concFront(rightAdjOrder);
1291 } else {
1292 adjOrder.conc(rightAdjOrder);
1293 }
1294 }
1295 m_gWinner->sort(vWinner, adjOrder);
1296}
1297}
Declaration of min-st-cut algorithm which calculates the min-st-cut of an st-planar graph by doing a ...
MinSTCutDijkstra class template.
Declaration of class StaticSPQRTree.
Declaration and implementation of list-based queues (classes QueuePure<E> and Queue<E>).
Class for adjacency list elements.
Definition Graph_d.h:79
adjEntry succ() const
Returns the successor in the adjacency list.
Definition Graph_d.h:155
edge theEdge() const
Returns the edge associated with this adjacency entry.
Definition Graph_d.h:97
Dynamic arrays indexed with adjacency entries.
Combinatorial embeddings of planar graphs with modification functionality.
Dynamic arrays indexed with edges.
Definition EdgeArray.h:125
Class for the representation of edges.
Definition Graph_d.h:300
This is a helper class to make the glueing of two edges simpler.
void mapLoserToNewWinnerEdge(edge eInLoser)
A mapping from the eInLoser graph to a new edge in the winner graph is created.
node getWinnerNodeOfLoserNode(node v) const
Getter for m_mapV_l2w.
const edge m_eWinner
The core edge that will survive.
GlueMap(edge eWinner, edge eLoser, NonPlanarCore< TCost > &npc)
A GlueMap is created from an NonPlanarCore and two core edges that ought to be glued together.
void mapLoserToWinnerNode(node vInLoser, node vInWinner)
A mapping from the vInLoser to the vInWinner is created.
NodeArray< node > m_mapV_l2w
A map from the nodes of the loser graph to their new home in the winner graph.
EdgeArray< edge > m_mapE_l2w
A map from the edges of the loser graph to their new home in the winner graph.
const Graph * m_gLoser
The graph that eLoser represents.
void reorder(node vLoser, bool sameDirection, bool isTNodeOfPNode)
This method reorders the adjacency order of vLoser's counterpart in the winner graph according to the...
const edge m_eLoser
The core edge that will be deleted.
const NodeArray< node > * m_mapVloser
A map from the nodes of the loser graph to the original graph, to denote the original of each node.
Graph * m_gWinner
The graph that eWinner represents.
NodeArray< node > * m_mapVwinner
A map from the nodes of the winner graph to the original graph, to denote the original of each edge.
EdgeArray< edge > * m_mapEwinner
A map from the edges of the winner graph to the original graph, to denote the original of each edge.
void mapLoserToNewWinnerNode(node vInLoser)
A mapping from the vInLoser to a new node in the winner graph is created.
NonPlanarCore< TCost > & m_npc
The NonPlanarCore on which this instance operates.
const EdgeArray< edge > * m_mapEloser
A map from the edges of the loser graph to the original graph, to denote the original of each node.
const Graph & getLoserGraph() const
Getter for m_gLoser.
Copies of graphs supporting edge splitting.
Definition GraphCopy.h:254
Data type for general directed graphs (adjacency list representation).
Definition Graph_d.h:521
void allNodes(CONTAINER &nodeContainer) const
Returns a container with all nodes of the graph.
Definition Graph_d.h:685
internal::GraphObjectContainer< EdgeElement > edges
The container containing all edge objects.
Definition Graph_d.h:592
Doubly linked lists (maintaining the length of the list).
Definition List.h:1435
int size() const
Returns the number of elements in the list.
Definition List.h:1472
void clear()
Removes all elements from the list.
Definition List.h:1610
iterator pushBack(const E &x)
Adds element x at the end of the list.
Definition List.h:1531
iterator begin()
Returns an iterator to the first element of the list.
Definition List.h:375
int pos(const_iterator it) const
Returns the position (starting with 0) of iterator it in the list.
Definition List.h:353
ListConstIterator< E > search(const E &e) const
Scans the list for the specified element and returns an iterator to the first occurrence in the list,...
Definition List.h:1264
iterator end()
Returns an iterator to one-past-last element of the list.
Definition List.h:393
Min-st-cut algorithm, that calculates the cut by doing a depth first search over the dual graph of of...
Definition MinSTCutBFS.h:54
Min-st-cut algorithm, that calculates the cut by calculating the shortest path between the faces adja...
Dynamic arrays indexed with nodes.
Definition NodeArray.h:125
void init()
Reinitializes the array. Associates the array with no graph.
Definition NodeArray.h:266
Class for the representation of nodes.
Definition Graph_d.h:177
internal::GraphObjectContainer< AdjElement > adjEntries
The container containing all entries in the adjacency list of this node.
Definition Graph_d.h:208
adjEntry firstAdj() const
Returns the first entry in the adjaceny list.
Definition Graph_d.h:223
Non-planar core reduction.
EdgeArray< List< CutEdge > > m_mincut
Traversing path for an edge in the core.
const Graph & originalGraph() const
Returns the original graph.
void glue(edge eWinner, edge eLoser)
Glues together the skeletons of eWinner and eLoser for pruned P- and S-nodes.
Graph m_graph
The core.
List< edge > original(edge e) const
Returns the edges of the original graph, which are represented by e in the core.
NodeArray< node > m_orig
Corresp. original node.
const EdgeArray< TCost > & cost() const
Returns the costs of the edges in the core, which is the number of original edges crossed,...
void traversingPath(const Skeleton &Sv, edge eS, List< CutEdge > &path, NodeArray< node > &mapV, edge coreEdge, const EdgeArray< TCost > *weight_src, MinSTCutModule< TCost > *minSTCutModule)
Computes the traversing path for a given edge and the unmarked tree rooted in the node of eS and save...
node tNode(edge e) const
Returns the t node of the skeleton of the st-component represented by the core edge e = (s,...
void inflateCrossing(node v)
The crossing denoted by dummy node v from the planarized copy of the core get inserted into the end g...
bool isVirtual(edge e) const
True iff the edge e in the core represents more than one orginal edge and therefore is virtual.
const GraphCopy * m_planarCore
A pointer to a copy of the core, in which crossings are replaced by dummy nodes.
const List< CutEdge > & mincut(edge e) const
Returns the mincut of the st-component represented by e.
void getAllMultiedges(List< edge > &winningEdges, List< edge > &losingEdges)
Checks for multiedges in the core.
void retransform(const GraphCopy &planarCore, GraphCopy &planarGraph, bool pCisPlanar=true)
Inserts the crossings from a copy of the core into a copy of the original graph.
const Graph * m_pOriginal
The original graph.
void markCore(NodeArray< bool > &mark)
Marks all nodes of the underlying SPQRTree and prunes planar leaves until the marked nodes span a tre...
node original(node v) const
Returns the node of the original graph, which is represented by v in the core.
EdgeArray< edge > * mapE(edge e) const
Returns a map from the edges of the st-component represented by the core edge e to the original graph...
void importEmbedding(edge e)
This method asserts that all parts of the end graph that are represented by edge e internally have th...
EdgeArray< node > m_tNode
The t node of the st-component of a core edge.
StaticSPQRTree m_T
The SPQRTree that represents the original graph.
NonPlanarCore(const Graph &G, const EdgeArray< TCost > &weight, MinSTCutModule< TCost > *minSTCutModule, bool nonPlanarityGuaranteed=false)
Algorithm call and constructor.
EdgeArray< node > m_sNode
The s node of the st-component of a core edge.
void call(const Graph &G, const EdgeArray< TCost > *weight, MinSTCutModule< TCost > *minSTCutModule, bool nonPlanarityGuaranteed)
The private method behind the constructors.
node sNode(edge e) const
Returns the s node of the skeleton of the st-component represented by the core edge e = (s,...
void normalizeCutEdgeDirection(edge coreEdge)
Every edge of coreEdge's cut that doesn't go the same direction as coreEdge gets reversed.
void glueMincuts(edge eWinner, edge eLoser)
Glues together the mincuts of the winner and the loser edge.
GraphCopy * m_endGraph
A pointer to a copy of the original graph, in which crossings are replaced by dummy nodes.
void splitEdgeIntoSections(edge e, List< node > &splitdummies)
To be able to insert crossings correctly, an end graph edge ought to be split into n-1 sections if n ...
NonPlanarCore(const Graph &G, bool nonPlanarityGuaranteed=false)
The unweighted version of the Algorithm call and constructor.
EdgeArray< NodeArray< node > * > m_mapV
The mapping between the nodes of each embedding and their original.
EdgeArray< TCost > m_cost
TCosts to cross each edge of the core.
const Graph & core() const
Returns the non-planar core.
void getMincut(edge e, List< edge > &cut)
Get the mincut of e with respect to its position in the chain of its original edge.
TCost cost(edge e) const
Returns the cost of e, which is the number of original edges crossed, if e is crossed,...
NonPlanarCore(const Graph &G, const EdgeArray< TCost > &weight, bool nonPlanarityGuaranteed=false)
An slimmed version of the Algorithm call and constructor.
EdgeArray< EdgeArray< edge > * > m_mapE
The mapping between the edges of each embedding and their original.
EdgeArray< Graph * > m_underlyingGraphs
The graph for the underlying skeleton of a virtual edge in the core.
edge realEdge(edge e) const
Returns the edge of the orginal graph, which is represented by e or nullptr iff e is virtual.
void removeSplitdummies(List< node > &splitdummies)
After inserting the crossings, the end graph edges don't need to be partitioned anymore so the splitd...
EdgeArray< edge > m_real
Corresp. original edge (0 if virtual)
The parameterized class Queue<E> implements list-based queues.
Definition Queue.h:200
Encapsulates a pointer to an ogdf::SList element.
Definition SList.h:92
bool valid() const
Returns true iff the iterator points to an element.
Definition SList.h:122
Singly linked lists.
Definition SList.h:179
iterator begin()
Returns an iterator to the first element of the list.
Definition SList.h:332
iterator pushBack(const E &x)
Adds element x at the end of the list.
Definition SList.h:469
Skeleton graphs of nodes in an SPQR-tree.
Definition Skeleton.h:59
Linear-time implementation of static SPQR-trees.
bool isBiconnected(const Graph &G, node &cutVertex)
Returns true iff G is biconnected.
void parallelFreeSortUndirected(const Graph &G, SListPure< edge > &edges, EdgeArray< int > &minIndex, EdgeArray< int > &maxIndex)
Sorts the edges of G such that undirected parallel edges come after each other in the list.
bool planarEmbed(Graph &G)
Returns true, if G is planar, false otherwise. If true is returned, G will be planarly embedded.
bool isPlanar(const Graph &G)
Returns true, if G is planar, false otherwise.
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
Definition basic.h:41
static MultilevelBuilder * getDoubleFactoredZeroAdjustedMerger()
The namespace for all OGDF objects.
@ tree
for every hyperedge e a minimal subcubic tree connecting all hypernodes incident with e together is a...
Declaration of simple graph algorithms.
Struct to represent an edge that needs to be crossed in order to cross an st-component.
const bool dir
true, iff the edge is directed from the s partition to the t partion
CutEdge(edge paramEdge, bool directed)
QueueEntry(node p, node v)
node m_parent
node m_current