6 * $Date: 2012-07-16 15:34:43 +0200 (Mo, 16. Jul 2012) $
7 ***************************************************************/
10 * \brief implementation of MMVariableEmbeddingInserter class
12 * \author Carsten Gutwenger
15 * This file is part of the Open Graph Drawing Framework (OGDF).
19 * See README.txt in the root directory of the OGDF installation for details.
22 * This program is free software; you can redistribute it and/or
23 * modify it under the terms of the GNU General Public License
24 * Version 2 or 3 as published by the Free Software Foundation;
25 * see the file LICENSE.txt included in the packaging of this file
29 * This program is distributed in the hope that it will be useful,
30 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 * GNU General Public License for more details.
35 * You should have received a copy of the GNU General Public
36 * License along with this program; if not, write to the Free
37 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
38 * Boston, MA 02110-1301, USA.
40 * \see http://www.gnu.org/copyleft/gpl.html
41 ***************************************************************/
44 #include <ogdf/planarity/MMVariableEmbeddingInserter.h>
45 #include <ogdf/basic/NodeSet.h>
46 #include <ogdf/basic/simple_graph_alg.h>
47 #include <ogdf/decomposition/StaticPlanarSPQRTree.h>
48 #include <ogdf/basic/extended_graph_alg.h>
49 #include <ogdf/basic/String.h>
50 #include <ogdf/basic/GraphAttributes.h>
57 static int globalCounter
= 0;
59 //---------------------------------------------------------
61 // sets default values for options
63 MMVariableEmbeddingInserter::MMVariableEmbeddingInserter()
66 m_percentMostCrossed
= 25;
70 //---------------------------------------------------------
72 // bucket function for sorting edges by decreasing number
74 class VEICrossingsBucket
: public BucketFunc
<edge
>
76 const PlanRepExpansion
*m_pPG
;
79 VEICrossingsBucket(const PlanRepExpansion
*pPG
) :
82 int getBucket(const edge
&e
) {
83 return -m_pPG
->chain(e
).size();
87 void outputPG(const PlanRepExpansion
&PG
, int i
)
89 GraphAttributes
AG(PG
, GraphAttributes::nodeLabel
);
94 label
.sprintf("%d",v
->index());
95 AG
.labelNode(v
) = label
;
99 str
.sprintf("PG_%d.gml", i
);
103 void MMVariableEmbeddingInserter::writeEip(const List
<Crossing
> &eip
)
105 ListConstIterator
<Crossing
> it
;
106 for(it
= eip
.begin(); it
.valid(); ++it
) {
107 const MMVariableEmbeddingInserter::Crossing
&cr
= *it
;
111 cout
<< cr
.m_partitionLeft
;
113 cout
<< cr
.m_partitionRight
;
122 //---------------------------------------------------------
123 // actual call (called by all variations of call)
124 // crossing of generalizations is forbidden if forbidCrossingGens = true
125 // edge costs are obeyed if costOrig != 0
127 Module::ReturnType
MMVariableEmbeddingInserter::doCall(
128 PlanRepExpansion
&PG
,
129 const List
<edge
> &origEdges
,
130 const EdgeArray
<bool> *forbiddenEdgeOrig
)
132 ReturnType retValue
= retFeasible
;
134 if (origEdges
.size() == 0)
135 return retOptimal
; // nothing to do
138 m_forbiddenEdgeOrig
= forbiddenEdgeOrig
;
140 SListPure
<edge
> rrEdges
;
141 if(removeReinsert() != rrNone
) {
144 rrEdges
.pushBack(PG
.originalEdge(e
));
146 ListConstIterator
<edge
> itE
;
147 for(itE
= origEdges
.begin(); itE
.valid(); ++itE
)
148 rrEdges
.pushBack(*itE
);
151 m_pSources
= new NodeSet(PG
);
152 m_pTargets
= new NodeSet(PG
);
159 // insertion of edges
160 ListConstIterator
<edge
> it
;
161 for(it
= origEdges
.begin(); it
.valid(); ++it
)
164 node srcOrig
= eOrig
->source();
165 node tgtOrig
= eOrig
->target();
168 cout
<< "insert " << srcOrig
<< " -> " << tgtOrig
<< endl
;
171 node oldSrc
= (PG
.splittableOrig(srcOrig
) && PG
.expansion(srcOrig
).size() == 1) ?
172 PG
.expansion(srcOrig
).front() : 0;
173 node oldTgt
= (PG
.splittableOrig(tgtOrig
) && PG
.expansion(tgtOrig
).size() == 1) ?
174 PG
.expansion(tgtOrig
).front() : 0;
176 anchorNodes(eOrig
->source(), *m_pSources
);
177 anchorNodes(eOrig
->target(), *m_pTargets
);
179 node vDummy
= commonDummy(*m_pSources
, *m_pTargets
);
181 edge eExtraSrc
= 0, eExtraTgt
= 0;
185 AnchorNodeInfo vStart
, vEnd
;
186 insert(eip
, vStart
, vEnd
);
191 preprocessInsertionPath(vStart
,vEnd
,srcOrig
,tgtOrig
,src
,tgt
,eExtraSrc
,eExtraTgt
);
194 cout
<< "from: " << src
<< " to: " << tgt
<< endl
;
198 insertWithCommonDummy(eOrig
, vDummy
, src
, tgt
);
200 cout
<< "(direct) from: " << src
<< " to: " << tgt
<< endl
;
204 PG
.insertEdgePath(eOrig
, 0, src
, tgt
, eip
, eExtraSrc
, eExtraTgt
);
215 if(oldSrc
!= 0 && PG
.expansion(srcOrig
).size() > 1)
216 contractSplitIfReq(oldSrc
);
217 if(oldTgt
!= 0 && PG
.expansion(tgtOrig
).size() > 1)
218 contractSplitIfReq(oldTgt
);
220 //OGDF_ASSERT(PG.consistencyCheck());
221 //OGDF_ASSERT(isPlanar(PG));
224 if(removeReinsert() != rrNone
) {
225 // postprocessing (remove-reinsert heuristc)
226 //SListPure<edge> rrEdges;
228 //switch(removeReinsert())
231 //case rrMostCrossed: {
232 // const List<node> &origInCC = PG.nodesInCC();
233 // ListConstIterator<node> itV;
235 // for(itV = origInCC.begin(); itV.valid(); ++itV) {
238 // forall_adj(adj,vG) {
239 // if ((adj->index() & 1) == 0) continue;
240 // edge eG = adj->theEdge();
241 // rrEdges.pushBack(eG);
248 // ListConstIterator<edge> it;
249 // for(it = origEdges.begin(); it.valid(); ++it)
250 // rrEdges.pushBack(*it);
255 // marks the end of the interval of rrEdges over which we iterate
256 // initially set to invalid iterator which means all edges
257 //SListConstIterator<edge> itStop;
263 //if(removeReinsert() == rrMostCrossed)
265 // VEICrossingsBucket bucket(&PG);
266 // rrEdges.bucketSort(bucket);
268 // const int num = int(0.01 * percentMostCrossed() * G.numberOfEdges());
269 // itStop = rrEdges.get(num);
272 SListConstIterator
<edge
> it
;
273 for(it
= rrEdges
.begin(); it
.valid(); ++it
)
277 node srcOrig
= eOrig
->source();
278 node tgtOrig
= eOrig
->target();
280 int oldCrossings
= PG
.chain(eOrig
).size() - 1;
281 if (oldCrossings
== 0) continue; // cannot improve
283 node oldSrc
= 0, oldTgt
= 0;
284 PG
.removeEdgePath(eOrig
,0,oldSrc
,oldTgt
);
285 //OGDF_ASSERT(PG.consistencyCheck());
287 // try to find a better insertion path
288 anchorNodes(eOrig
->source(), *m_pSources
);
289 anchorNodes(eOrig
->target(), *m_pTargets
);
291 node vDummy
= commonDummy(*m_pSources
, *m_pTargets
);
293 edge eExtraSrc
= 0, eExtraTgt
= 0;
297 AnchorNodeInfo vStart
, vEnd
;
298 insert(eip
, vStart
, vEnd
);
299 preprocessInsertionPath(vStart
,vEnd
,srcOrig
,tgtOrig
,src
,tgt
,eExtraSrc
,eExtraTgt
);
302 insertWithCommonDummy(eOrig
, vDummy
, src
, tgt
);
305 int newCrossings
= eip
.size();
307 OGDF_ASSERT(isPlanar(PG
));
308 PG
.insertEdgePath(eOrig
, 0, src
, tgt
, eip
, eExtraSrc
, eExtraTgt
);
309 OGDF_ASSERT(PG
.consistencyCheck());
310 OGDF_ASSERT(isPlanar(PG
));
315 if(PG
.splittable(oldSrc
))
316 contractSplitIfReq(oldSrc
);
317 if(PG
.splittable(oldTgt
))
318 contractSplitIfReq(oldTgt
);
320 OGDF_ASSERT(PG
.consistencyCheck());
321 OGDF_ASSERT(isPlanar(PG
));
323 //int newPathLength = PG.chain(eOrig).size() - 1;
324 int saved
= oldCrossings
- newCrossings
;
325 OGDF_ASSERT(saved
>= 0);
331 if(removeReinsert() == rrAll
)
333 // process all node splits
334 int nsCount
= PG
.nodeSplits().size();
335 ListIterator
<PlanRepExpansion::NodeSplit
> itS
, itSNext
;
336 for(itS
= PG
.nodeSplits().begin(); itS
.valid() && nsCount
> 0; itS
= itSNext
, --nsCount
)
339 PlanRepExpansion::NodeSplit
*ns
= &(*itS
);
341 int oldCrossings
= ns
->m_path
.size() - 1;
342 if (oldCrossings
== 0) {
343 itSNext
= itS
.succ();
344 PG
.contractSplit(ns
);
345 continue; // cannot improve
348 node vOrig
= PG
.original(ns
->source());
350 node oldSrc
= 0, oldTgt
= 0;
351 PG
.removeEdgePath(0,ns
,oldSrc
,oldTgt
);
352 OGDF_ASSERT(PG
.consistencyCheck());
354 // try to find a better insertion path
355 findSourcesAndTargets(oldSrc
,oldTgt
,*m_pSources
,*m_pTargets
);
357 node vCommon
= commonDummy(*m_pSources
, *m_pTargets
);
361 edge eExtraSrc
= 0, eExtraTgt
= 0;
364 AnchorNodeInfo vStart
, vEnd
;
365 insert(eip
, vStart
, vEnd
);
366 preprocessInsertionPath(vStart
,vEnd
,vOrig
,vOrig
,src
,tgt
,eExtraSrc
,eExtraTgt
);
367 PG
.insertEdgePath(0, ns
, src
, tgt
, eip
, eExtraSrc
, eExtraTgt
);
369 OGDF_ASSERT(PG
.consistencyCheck());
374 if(PG
.splittable(oldSrc
))
375 contractSplitIfReq(oldSrc
);
376 if(PG
.splittable(oldTgt
))
377 contractSplitIfReq(oldTgt
);
379 OGDF_ASSERT(PG
.consistencyCheck());
380 OGDF_ASSERT(isPlanar(PG
));
382 //int newCrossings = ns->m_path.size() - 1;
383 int newCrossings
= eip
.size();
384 int saved
= oldCrossings
- newCrossings
;
385 OGDF_ASSERT(saved
>= 0);
390 itSNext
= itS
.succ();
391 if(ns
->m_path
.size() == 1)
392 PG
.contractSplit(ns
);
399 itSNext
= itS
.succ();
401 convertDummy(vCommon
,vOrig
,ns
);
402 OGDF_ASSERT(PG
.consistencyCheck());
403 OGDF_ASSERT(isPlanar(PG
));
418 OGDF_ASSERT(isPlanar
);
419 OGDF_ASSERT(PG
.representsCombEmbedding());
425 void MMVariableEmbeddingInserter::insert(
427 AnchorNodeInfo
&vStart
,
428 AnchorNodeInfo
&vEnd
)
430 PlanRepExpansion
&PG
= *m_pPG
;
433 // compute biconnected components of PG
434 EdgeArray
<int> compnum(PG
);
435 int c
= biconnectedComponents(PG
,compnum
);
440 // edgeB[i] = list of edges in component i
444 m_edgeB
[compnum
[e
]].pushBack(e
);
446 // construct arrays compV and nodeB such that
447 // m_compV[v] = list of components containing v
448 // m_nodeB[i] = list of vertices in component i
449 NodeArray
<bool> mark(PG
,false);
452 for(i
= 0; i
< c
; ++i
) {
453 SListConstIterator
<edge
> itEdge
;
454 for(itEdge
= m_edgeB
[i
].begin(); itEdge
.valid(); ++itEdge
)
458 if (!mark
[e
->source()]) {
459 mark
[e
->source()] = true;
460 m_nodeB
[i
].pushBack(e
->source());
462 if (!mark
[e
->target()]) {
463 mark
[e
->target()] = true;
464 m_nodeB
[i
].pushBack(e
->target());
468 SListConstIterator
<node
> itNode
;
469 for(itNode
= m_nodeB
[i
].begin(); itNode
.valid(); ++itNode
)
472 m_compV
[v
].pushBack(i
);
480 m_conFinished
= false;
481 dfsVertex(m_pTargets
->nodes().front(), -1, eip
, vStart
, vEnd
);
483 // deallocate resources used by insert()
491 node
MMVariableEmbeddingInserter::prepareAnchorNode(
492 const AnchorNodeInfo
&anchor
,
497 PlanRepExpansion
&PG
= *m_pPG
;
503 PlanRepExpansion::NodeSplit
*nsStraight
;
504 if(anchor
.m_adj_2
!= 0) {
505 adj
= anchor
.m_adj_1
;
506 //if(PG.originalEdge(adj->theEdge()) == PG.originalEdge(anchor.m_adj_2->theEdge()) &&
507 // PG.nodeSplitOf(adj->theEdge()) == PG.nodeSplitOf(anchor.m_adj_2->theEdge()))
509 // node u = adj->theNode();
510 // forall_adj(adj,u) {
511 // List<edge> *pathStraight = &PG.setOrigs(adj->theEdge(), eStraight, nsStraight);
512 // vStraight = pathStraight->front()->source();
513 // if(PG.original(vStraight) == vOrig)
515 // vStraight = pathStraight->back()->target();
516 // if(PG.original(vStraight)== vOrig)
520 // PG.removeCrossingReuseDummy(adj, vStraight);
525 List
<edge
> *pathStraight
= &PG
.setOrigs(adj
->theEdge(), eStraight
, nsStraight
);
527 vStraight
= pathStraight
->front()->source();
528 if(PG
.original(vStraight
) != vOrig
) {
529 vStraight
= pathStraight
->back()->target();
530 if(PG
.original(vStraight
) != vOrig
) {
531 adj
= anchor
.m_adj_2
;
532 pathStraight
= &PG
.setOrigs(adj
->theEdge(), eStraight
, nsStraight
);
533 vStraight
= pathStraight
->front()->source();
534 if(PG
.original(vStraight
) != vOrig
) {
535 vStraight
= pathStraight
->back()->target();
540 if(PG
.original(vStraight
) != vOrig
) {
541 node u
= adj
->theNode();
545 forall_adj(adj_x
,u
) {
546 if(adj_x
!= anchor
.m_adj_1
&& adj_x
!= anchor
.m_adj_2
)
550 List
<edge
> *pathStraight
= &PG
.setOrigs(adjA
[0]->theEdge(), eStraight
, nsStraight
);
551 vStraight
= pathStraight
->front()->source();
552 if(PG
.original(vStraight
) != vOrig
)
553 vStraight
= pathStraight
->back()->target();
554 OGDF_ASSERT(PG
.original(vStraight
) == vOrig
);
556 eExtra
= PG
.separateDummy(adjA
[0], adjA
[1], vStraight
, isSrc
);
561 // Should be the correct adj... (case S-node, dummy)
562 adj
= anchor
.m_adj_1
;
563 List
<edge
> *pathStraight
= &PG
.setOrigs(adj
->theEdge(), eStraight
, nsStraight
);
565 if((eStraight
&& eStraight
->source() != vOrig
&& eStraight
->target() != vOrig
) ||
566 (nsStraight
&& PG
.original(nsStraight
->source()) != vOrig
))
568 node vDummy
= adj
->theNode();
569 edge eStraightOld
= eStraight
;
570 PlanRepExpansion::NodeSplit
*nsStraightOld
= nsStraight
;
572 forall_adj(adj
,vDummy
) {
573 pathStraight
= &PG
.setOrigs(adj
->theEdge(), eStraight
, nsStraight
);
574 if((eStraightOld
&& eStraight
!= eStraightOld
) || (nsStraightOld
&& nsStraight
!= nsStraightOld
))
579 vStraight
= pathStraight
->front()->source();
580 if(PG
.original(vStraight
) != vOrig
)
581 vStraight
= pathStraight
->back()->target();
584 OGDF_ASSERT(PG
.original(vStraight
) == vOrig
);
587 if(PG
.original(adj
->twinNode()) == vOrig
) {
588 // No need for a split; can just directly go to a split node
589 return adj
->twinNode();
592 edge e
= adj
->theEdge();
593 if(nsStraight
== 0) {
594 // We split a chain of an original edge
595 PG
.enlargeSplit(vStraight
, e
);
599 // We split a node split
600 PG
.splitNodeSplit(e
);
606 void MMVariableEmbeddingInserter::preprocessInsertionPath(
607 const AnchorNodeInfo
&srcInfo
,
608 const AnchorNodeInfo
&tgtInfo
,
616 PlanRepExpansion
&PG
= *m_pPG
;
618 src
= srcInfo
.m_adj_1
->theNode();
619 if(PG
.original(src
) == 0)
620 src
= prepareAnchorNode(srcInfo
,srcOrig
,true,eSrc
);
622 tgt
= tgtInfo
.m_adj_1
->theNode();
623 if(PG
.original(tgt
) == 0)
624 tgt
= prepareAnchorNode(tgtInfo
,tgtOrig
,false,eTgt
);
628 node
MMVariableEmbeddingInserter::preparePath(
634 PlanRepExpansion
&PG
= *m_pPG
;
636 if(PG
.original(adjPath
->twinNode()) == vOrig
) {
637 // No need for a split; can just directly go to a split node
638 return adjPath
->twinNode();
641 edge e
= adjPath
->theEdge();
643 // We split a chain of an original edge
644 PG
.enlargeSplit(vAnchor
, e
);
646 // We split a node split
647 PG
.splitNodeSplit(e
);
654 void MMVariableEmbeddingInserter::findPseudos(
657 AnchorNodeInfo
&infoSrc
,
658 SListPure
<node
> &pseudos
)
660 PlanRepExpansion
&PG
= *m_pPG
;
662 ListConstIterator
<edge
> it
= PG
.position(adjSrc
->theEdge());
664 if((*it
)->source() == vDummy
) {
666 while(PG
.isPseudoCrossing(w
= e
->target())) {
671 infoSrc
.m_adj_1
= e
->adjTarget();
672 infoSrc
.m_adj_2
= (adjSrc
->cyclicSucc() == (*PG
.position(adjSrc
->theEdge()).pred())->adjTarget()) ?
673 infoSrc
.m_adj_1
->cyclicSucc() : infoSrc
.m_adj_1
->cyclicPred();
677 while(PG
.isPseudoCrossing(w
= e
->source())) {
682 infoSrc
.m_adj_1
= e
->adjSource();
683 infoSrc
.m_adj_2
= (adjSrc
->cyclicPred() == (*PG
.position(adjSrc
->theEdge()).succ())->adjSource()) ?
684 infoSrc
.m_adj_1
->cyclicPred() : infoSrc
.m_adj_1
->cyclicSucc();
690 void MMVariableEmbeddingInserter::insertWithCommonDummy(
696 PlanRepExpansion
&PG
= *m_pPG
;
701 OGDF_ASSERT(isPlanar
);
703 node vSrc
= 0, vTgt
= 0;
704 adjEntry adjSrc
= 0, adjTgt
= 0;
705 bool bOrigEdgeSrc
= true, bOrigEdgeTgt
= true;
708 forall_adj(adj
,vDummy
) {
709 edge e
= adj
->theEdge();
711 PlanRepExpansion::NodeSplit
*nsStraight
;
712 List
<edge
> &pathStraight
= PG
.setOrigs(e
, eStraight
, nsStraight
);
715 if(vDummy
== e
->source())
716 vAnchor
= pathStraight
.back()->target();
718 vAnchor
= pathStraight
.front()->source();
720 node vOrig
= PG
.original(vAnchor
);
721 if(vOrig
== eOrig
->source()) {
724 bOrigEdgeSrc
= (eStraight
!= 0);
725 } else if(vOrig
== eOrig
->target()) {
728 bOrigEdgeTgt
= (eStraight
!= 0);
732 OGDF_ASSERT(vSrc
!= 0 && vTgt
!= 0 && adjSrc
!= 0 && adjTgt
!= 0);
734 if(adjSrc
== adjTgt
->cyclicPred() || adjSrc
== adjTgt
->cyclicSucc())
736 src
= preparePath(vSrc
, adjSrc
, bOrigEdgeSrc
, eOrig
->source());
737 tgt
= preparePath(vTgt
, adjTgt
, bOrigEdgeTgt
, eOrig
->target());
740 SListPure
<node
> pseudos
;
741 AnchorNodeInfo infoSrc
;
742 AnchorNodeInfo infoTgt
;
744 findPseudos(vDummy
,adjSrc
,infoSrc
,pseudos
);
745 findPseudos(vDummy
,adjTgt
,infoTgt
,pseudos
);
747 SListConstIterator
<node
> it
;
748 for(it
= pseudos
.begin(); it
.valid(); ++it
)
749 PG
.resolvePseudoCrossing(*it
);
752 src
= infoSrc
.m_adj_1
->theNode();
753 if(PG
.original(src
) == 0)
754 src
= prepareAnchorNode(infoSrc
,eOrig
->source(),true,eExtra
);
755 OGDF_ASSERT(eExtra
== 0);
757 tgt
= infoTgt
.m_adj_1
->theNode();
758 if(PG
.original(tgt
) == 0)
759 tgt
= prepareAnchorNode(infoTgt
,eOrig
->target(),false,eExtra
);
760 OGDF_ASSERT(eExtra
== 0);
764 //adjEntry adjTgt_2 = adjTgt->cyclicSucc()->cyclicSucc();
765 //OGDF_ASSERT(PG.nodeSplitOf(adjTgt->theEdge()) == PG.nodeSplitOf(adjTgt_2->theEdge()) &&
766 // PG.originalEdge(adjTgt->theEdge()) == PG.originalEdge(adjTgt_2->theEdge()));
768 //edge e = PG.insertBySepDummy(eOrig, vSrc, vTgt, adjSrc, adjTgt, adjTgt_2);
769 // //separateDummy(adjTgt, adjTgt_2, vTgt, false);
770 //PG.assignOrig(e,eOrig);
774 //-------------------------------------------------------------------
775 // Block represents a block of the original graph
776 //-------------------------------------------------------------------
778 class MMVariableEmbeddingInserter::Block
: public Graph
782 Block(PlanRepExpansion
&PG
) : m_PG(PG
)
784 m_adjBCtoG
.init(*this,0);
785 m_forbidden
.init(*this,false);
786 m_vBCtoG
.init(*this,0);
787 m_isSource
.init(*this,false);
788 m_isTarget
.init(*this,false);
789 m_isSplittable
.init(*this,false);
793 ~Block() { delete m_pT
; }
795 // avoid automatic generation of assignment operator
796 Block
&operator=(const Block
&);
798 node
containsSource(node v
) const;
799 node
containsTarget(node v
) const;
801 adjEntry
containsSourceAdj(node v
) const;
802 adjEntry
containsTargetAdj(node v
) const;
804 PlanRepExpansion
&m_PG
;
805 StaticPlanarSPQRTree
*m_pT
;
807 AdjEntryArray
<adjEntry
> m_adjBCtoG
;
808 EdgeArray
<bool> m_forbidden
;
809 NodeArray
<node
> m_vBCtoG
;
811 NodeArray
<bool> m_isSource
;
812 NodeArray
<bool> m_isTarget
;
813 NodeArray
<bool> m_isSplittable
;
817 node
MMVariableEmbeddingInserter::Block::containsSource(node v
) const
819 const Skeleton
&S
= m_pT
->skeleton(v
);
820 const Graph
&M
= S
.getGraph();
824 node wOrig
= S
.original(w
);
825 if(m_isSource
[wOrig
])
832 node
MMVariableEmbeddingInserter::Block::containsTarget(node v
) const
834 const Skeleton
&S
= m_pT
->skeleton(v
);
835 const Graph
&M
= S
.getGraph();
839 node wOrig
= S
.original(w
);
840 if(m_isTarget
[wOrig
])
847 adjEntry
MMVariableEmbeddingInserter::Block::containsSourceAdj(node v
) const
849 const Skeleton
&S
= m_pT
->skeleton(v
);
850 const Graph
&M
= S
.getGraph();
854 wOrig
= S
.original(w
);
855 if(m_isSource
[wOrig
])
859 if(wOrig
== 0) return 0;
862 forall_adj(adj
,wOrig
) {
863 if(m_pT
->skeletonOfReal(adj
->theEdge()).treeNode() == v
)
867 return wOrig
->firstAdj();
870 adjEntry
MMVariableEmbeddingInserter::Block::containsTargetAdj(node v
) const
872 const Skeleton
&S
= m_pT
->skeleton(v
);
873 const Graph
&M
= S
.getGraph();
877 wOrig
= S
.original(w
);
878 if(m_isTarget
[wOrig
])
882 if(wOrig
== 0) return 0;
885 forall_adj(adj
,wOrig
) {
886 if(m_pT
->skeletonOfReal(adj
->theEdge()).treeNode() == v
)
890 return wOrig
->firstAdj();
894 //-------------------------------------------------------------------
895 // ExpandedSkeleton represents the (partially) expanded skeleton with
896 // its dual graph (search network)
897 //-------------------------------------------------------------------
899 class MMVariableEmbeddingInserter::ExpandedSkeleton
903 NodeArray
<node
> m_GtoExp
;
905 Graph m_exp
; // expanded graph
906 AdjEntryArray
<adjEntry
> m_expToG
;
907 edge m_eS
, m_eT
; // (virtual) edges in exp representing s and t (if any)
909 ConstCombinatorialEmbedding m_E
; //!< Embedding of expanded graph.
911 Graph m_dual
; //!< Search network of expanded skeleton.
912 NodeArray
<node
> m_primalNode
; //!< The node in PG corresponding to dual node (0 if face).
913 EdgeArray
<adjEntry
> m_primalAdj
; //!< The adjacency entry in primal graph corresponding to edge in dual.
914 EdgeArray
<int> m_dualCost
; //!< The cost of an edge in the seach network.
925 ExpandedSkeleton(Block
&BC
) :
927 m_GtoExp(BC
.m_pT
->originalGraph(),0),
929 m_primalNode(m_dual
,0),
930 m_primalAdj(m_dual
,0),
931 m_dualCost(m_dual
,0) { }
933 void expand(node v
, edge eIn
, edge eOut
);
935 void constructDual(bool bPathToEdge
, bool bPathToSrc
, bool bPathToTgt
);
937 void findShortestPath(bool &bPathToEdge
, bool &bPathToSrc
, bool &bPathToTgt
, Paths
&paths
);
939 // avoid automatic generation of assignment operator
940 ExpandedSkeleton
&operator=(const ExpandedSkeleton
&);
943 edge
insertEdge(node vG
, node wG
, edge eG
);
944 void expandSkeleton(node v
, edge e1
, edge e2
);
946 static void addOutgoingEdges(node v
, SListPure
<edge
> &edges
);
947 PathType
reconstructInsertionPath(
949 AnchorNodeInfo
&m_srcInfo
,
950 AnchorNodeInfo
&m_tgtInfo
,
951 List
<Crossing
> &crossed
,
952 SList
<adjEntry
> &addLeft
,
953 SList
<adjEntry
> &addRight
,
954 NodeArray
<edge
> &spPred
);
958 //-------------------------------------------------------------------
959 // build expanded graph (by expanding skeleton(v), edges eIn and eOut
960 // are the adjacent tree edges on the path from v1 to v2
961 //-------------------------------------------------------------------
963 void MMVariableEmbeddingInserter::ExpandedSkeleton::expand(
964 node v
, edge eIn
, edge eOut
)
968 while (!m_nodesG
.empty())
969 m_GtoExp
[m_nodesG
.popBackRet()] = 0;
971 const StaticSPQRTree
&T
= *m_BC
.m_pT
;
972 const Skeleton
&S
= T
.skeleton(v
);
976 edge eInS
= (v
!= eIn
->source()) ? T
.skeletonEdgeTgt(eIn
) :
977 T
.skeletonEdgeSrc(eIn
);
978 node x
= S
.original(eInS
->source()), y
= S
.original(eInS
->target());
979 m_eS
= insertEdge(x
,y
,0);
984 edge eOutS
= (v
!= eOut
->source()) ? T
.skeletonEdgeTgt(eOut
) :
985 T
.skeletonEdgeSrc(eOut
);
986 node x
= S
.original(eOutS
->source()), y
= S
.original(eOutS
->target());
987 m_eT
= insertEdge(x
,y
,0);
990 expandSkeleton(v
, eIn
, eOut
);
997 //-------------------------------------------------------------------
998 // insert edge in exp (from a node corresponding to vG in G to a node
999 // corresponding to wG)
1000 //-------------------------------------------------------------------
1002 edge
MMVariableEmbeddingInserter::ExpandedSkeleton::insertEdge(
1003 node vG
, node wG
, edge eG
)
1005 node
&rVG
= m_GtoExp
[vG
];
1006 node
&rWG
= m_GtoExp
[wG
];
1009 rVG
= m_exp
.newNode();
1010 m_nodesG
.pushBack(vG
);
1013 rWG
= m_exp
.newNode();
1014 m_nodesG
.pushBack(wG
);
1017 edge e1
= m_exp
.newEdge(rVG
,rWG
);
1020 m_expToG
[e1
->adjSource()] = eG
->adjSource();
1021 m_expToG
[e1
->adjTarget()] = eG
->adjTarget();
1023 m_expToG
[e1
->adjSource()] = 0;
1024 m_expToG
[e1
->adjTarget()] = 0;
1031 //-------------------------------------------------------------------
1032 // expand one skeleton (recursive construction)
1033 //-------------------------------------------------------------------
1035 void MMVariableEmbeddingInserter::ExpandedSkeleton::expandSkeleton(
1036 node v
, edge e1
, edge e2
)
1038 const StaticSkeleton
&S
= *dynamic_cast<StaticSkeleton
*>(&m_BC
.m_pT
->skeleton(v
));
1039 const Graph
&M
= S
.getGraph();
1044 edge eG
= S
.realEdge(e
);
1046 insertEdge(eG
->source(),eG
->target(),eG
);
1049 edge eT
= S
.treeEdge(e
);
1051 // do not expand virtual edges corresponding to tree edges e1 or e2
1052 if (eT
!= e1
&& eT
!= e2
) {
1053 expandSkeleton((v
== eT
->source()) ? eT
->target() : eT
->source(),
1061 //-------------------------------------------------------------------
1062 // construct augmented dual graph (search network)
1063 //-------------------------------------------------------------------
1065 void MMVariableEmbeddingInserter::ExpandedSkeleton::constructDual(
1066 bool bPathToEdge
, bool bPathToSrc
, bool bPathToTgt
)
1070 // insert a node in the dual graph for each face in E
1071 FaceArray
<node
> dualOfFace(m_E
);
1075 dualOfFace
[f
] = m_dual
.newNode();
1077 SListPure
<node
> sources
, targets
;
1079 // insert a node in the dual graph for each splittable node in PG
1080 NodeArray
<node
> dualOfNode(m_exp
,0);
1082 ListConstIterator
<node
> itV
;
1083 for(itV
= m_nodesG
.begin(); itV
.valid(); ++itV
) {
1085 node v
= m_GtoExp
[vBC
];
1087 bool addDualNode
= m_BC
.m_isSplittable
[vBC
];
1089 if(m_BC
.m_isSource
[vBC
]) {
1090 sources
.pushBack(v
);
1093 if(m_BC
.m_isTarget
[vBC
]) {
1094 targets
.pushBack(v
);
1099 m_primalNode
[dualOfNode
[v
] = m_dual
.newNode()] = v
;
1102 // Insert an edge into the dual graph for each adjacency entry in E.
1103 // The edges are directed from the left face to the right face.
1105 forall_nodes(v
,m_exp
)
1107 node vDual
= dualOfNode
[v
];
1112 // cannot cross virtual edge representing sources / targets
1113 adjEntry adjBC
= m_expToG
[adj
];
1117 node vLeft
= dualOfFace
[m_E
.leftFace (adj
)];
1118 node vRight
= dualOfFace
[m_E
.rightFace(adj
)];
1120 if(m_BC
.m_forbidden
[adjBC
->theEdge()] == false) {
1121 edge e
= m_dual
.newEdge(vLeft
,vRight
);
1122 m_primalAdj
[e
] = adj
;
1127 //if(m_eT == 0 || (v != m_eT->source() && v != m_eT->target())) {
1128 edge eOut
= m_dual
.newEdge(vDual
,vLeft
);
1129 m_primalAdj
[eOut
] = adj
;
1130 m_dualCost
[eOut
] = 0;
1134 ((bPathToSrc
== false || v
!= m_eS
->source()) && (bPathToTgt
== false || v
!= m_eS
->target())))
1136 edge eIn
= m_dual
.newEdge(vLeft
,vDual
);
1137 m_primalAdj
[eIn
] = adj
;
1138 m_dualCost
[eIn
] = 1;
1144 m_startEdge
= (bPathToEdge
) ? m_dual
.newNode() : 0;
1147 m_dual
.newEdge(m_startEdge
, dualOfFace
[m_E
.rightFace(m_eS
->adjSource())]);
1148 m_dual
.newEdge(m_startEdge
, dualOfFace
[m_E
.rightFace(m_eS
->adjTarget())]);
1151 m_startSource
= (bPathToSrc
) ? dualOfNode
[m_eS
->source()] : 0;
1152 m_startTarget
= (bPathToTgt
) ? dualOfNode
[m_eS
->target()] : 0;
1155 m_startSource
= m_startTarget
= 0;
1156 SListConstIterator
<node
> it
;
1157 for(it
= sources
.begin(); it
.valid(); ++it
)
1158 m_dual
.newEdge(m_startEdge
, dualOfNode
[*it
]);
1161 m_endEdge
= m_dual
.newNode();
1163 m_dual
.newEdge(dualOfFace
[m_E
.rightFace(m_eT
->adjSource())], m_endEdge
);
1164 m_dual
.newEdge(dualOfFace
[m_E
.rightFace(m_eT
->adjTarget())], m_endEdge
);
1166 m_endSource
= dualOfNode
[m_eT
->source()];
1167 m_endTarget
= dualOfNode
[m_eT
->target()];
1170 m_endSource
= m_endTarget
= 0;
1171 SListConstIterator
<node
> it
;
1172 for(it
= targets
.begin(); it
.valid(); ++it
)
1173 m_dual
.newEdge(dualOfNode
[*it
], m_endEdge
);
1178 //-------------------------------------------------------------------
1179 // finds shortest paths in the search network
1180 //-------------------------------------------------------------------
1182 void MMVariableEmbeddingInserter::ExpandedSkeleton::addOutgoingEdges(
1183 node v
, SListPure
<edge
> &edges
)
1186 forall_adj_edges(e
,v
)
1187 if(e
->target() != v
)
1191 MMVariableEmbeddingInserter::PathType
1192 MMVariableEmbeddingInserter::ExpandedSkeleton::reconstructInsertionPath(
1194 AnchorNodeInfo
&srcInfo
,
1195 AnchorNodeInfo
&tgtInfo
,
1196 List
<Crossing
> &crossed
,
1197 SList
<adjEntry
> &addLeft
,
1198 SList
<adjEntry
> &addRight
,
1199 NodeArray
<edge
> &spPred
)
1201 // handle last node on path split first
1202 if(v
== m_endEdge
) {
1203 edge eDual
= spPred
[v
];
1204 v
= eDual
->source();
1205 if(m_primalNode
[v
] != 0) {
1207 // hier Ziel speichern: m_expToG[m_primalAdj[eDual]]->theNode()
1208 //tgt = m_expToG[m_primalAdj[eDual]]->theNode();
1209 tgtInfo
.m_adj_1
= m_expToG
[m_primalAdj
[eDual
]];
1210 tgtInfo
.m_adj_2
= m_expToG
[m_primalAdj
[eDual
]->cyclicPred()];
1212 OGDF_ASSERT(tgtInfo
.m_adj_1
!= 0);
1214 v
= eDual
->source();
1218 edge eDual
= spPred
[v
];
1221 adjEntry adj_1
= m_primalAdj
[eDual
];
1222 Crossing
&cr
= *crossed
.pushFront(Crossing());
1225 for(adj
= adj_1
; adj
->theEdge() != m_eT
; adj
= adj
->cyclicSucc()) {
1226 adjEntry adjBC
= m_expToG
[adj
];
1228 cr
.m_partitionLeft
.pushBack(adjBC
);
1229 //OGDF_ASSERT(m_expToG[adj] != 0);
1231 for(adj
= adj
->cyclicSucc(); adj
!= adj_1
; adj
= adj
->cyclicSucc()) {
1232 adjEntry adjBC
= m_expToG
[adj
];
1234 cr
.m_partitionRight
.pushBack(adjBC
);
1235 //OGDF_ASSERT(m_expToG[adj] != 0);
1238 v
= eDual
->source();
1241 node vExp
= m_primalNode
[v
];
1242 OGDF_ASSERT(m_eS
->source() == vExp
|| m_eS
->target() == vExp
);
1243 OGDF_ASSERT(m_eT
->source() == vExp
|| m_eT
->target() == vExp
);
1244 adjEntry adjS
= (m_eS
->source() == vExp
) ? m_eS
->adjSource() : m_eS
->adjTarget();
1245 adjEntry adjT
= (m_eT
->source() == vExp
) ? m_eT
->adjSource() : m_eT
->adjTarget();
1246 OGDF_ASSERT(adjS
->theNode() == vExp
&& adjT
->theNode() == vExp
);
1249 for(adj
= adjS
->cyclicSucc(); adj
!= adjT
; adj
= adj
->cyclicSucc()) {
1250 addLeft
.pushBack(m_expToG
[adj
]);
1251 OGDF_ASSERT(m_expToG
[adj
] != 0);
1253 for(adj
= adj
->cyclicSucc(); adj
!= adjS
; adj
= adj
->cyclicSucc()) {
1254 addRight
.pushBack(m_expToG
[adj
]);
1255 OGDF_ASSERT(m_expToG
[adj
] != 0);
1260 while(v
!= m_startEdge
&& v
!= m_startSource
&& v
!= m_startTarget
) {
1261 OGDF_ASSERT(m_primalNode
[v
] == 0);
1263 edge eDual
= spPred
[v
];
1264 node w
= eDual
->source();
1266 if(m_primalNode
[w
] == 0) {
1268 adjEntry adjExp
= m_primalAdj
[spPred
[v
]];
1270 crossed
.pushFront(Crossing(m_expToG
[adjExp
]));
1273 edge eDual2
= spPred
[w
];
1276 adjEntry adj_1
= m_primalAdj
[eDual2
];
1277 adjEntry adj_2
= m_primalAdj
[eDual
];
1279 w
= eDual2
->source();
1281 Crossing
&cr
= *crossed
.pushFront(Crossing());
1284 for(adj
= adj_1
; adj
!= adj_2
; adj
= adj
->cyclicSucc()) {
1285 adjEntry adjBC
= m_expToG
[adj
];
1287 cr
.m_partitionLeft
.pushBack(adjBC
);
1288 //OGDF_ASSERT(m_expToG[adj] != 0);
1290 for(; adj
!= adj_1
; adj
= adj
->cyclicSucc()) {
1291 adjEntry adjBC
= m_expToG
[adj
];
1293 cr
.m_partitionRight
.pushBack(adjBC
);
1294 //OGDF_ASSERT(m_expToG[adj] != 0);
1298 // speichere Startkonoten hier:
1299 //src = m_expToG[m_primalAdj[eDual]]->theNode();
1300 srcInfo
.m_adj_1
= m_expToG
[m_primalAdj
[eDual
]];
1301 srcInfo
.m_adj_2
= m_expToG
[m_primalAdj
[eDual
]->cyclicPred()];
1303 OGDF_ASSERT(srcInfo
.m_adj_1
!= 0);
1307 adjEntry adj_2
= m_primalAdj
[eDual
];
1310 for(adj
= adj_2
; adj
->theEdge() != m_eS
; adj
= adj
->cyclicSucc()) {
1311 adjEntry adjBC
= m_expToG
[adj
];
1313 addLeft
.pushBack(adjBC
);
1314 //OGDF_ASSERT(m_expToG[adj] != 0);
1316 for(adj
= adj
->cyclicSucc(); adj
!= adj_2
; adj
= adj
->cyclicSucc()) {
1317 adjEntry adjBC
= m_expToG
[adj
];
1319 addRight
.pushBack(adjBC
);
1320 //OGDF_ASSERT(m_expToG[adj] != 0);
1328 if(v
== m_startEdge
)
1330 else if (v
== m_startSource
)
1331 return pathToSource
;
1333 return pathToTarget
;
1336 void MMVariableEmbeddingInserter::ExpandedSkeleton::findShortestPath(
1342 const int maxCost
= 2;
1344 Array
<SListPure
<edge
> > nodesAtDist(maxCost
);
1345 NodeArray
<edge
> spPred(m_dual
,0);
1349 addOutgoingEdges(m_startEdge
, nodesAtDist
[0]);
1351 addOutgoingEdges(m_startSource
, nodesAtDist
[0]);
1353 addOutgoingEdges(m_startTarget
, nodesAtDist
[0]);
1355 bool vEdgeReached
= false;
1356 bool vSourceReached
= (m_endSource
== 0 || m_endSource
== m_startSource
|| m_endSource
== m_startTarget
);
1357 bool vTargetReached
= (m_endTarget
== 0 || m_endTarget
== m_startSource
|| m_endTarget
== m_startTarget
);
1359 // actual search (using extended bfs on directed dual)
1360 int currentDist
= 0;
1364 // next candidate edge
1365 while(nodesAtDist
[currentDist
% maxCost
].empty())
1368 edge eCand
= nodesAtDist
[currentDist
% maxCost
].popFrontRet();
1369 node v
= eCand
->target();
1371 // leads to an unvisited node?
1374 // yes, then we set v's predecessor in search tree
1376 if(v
== m_endEdge
) vEdgeReached
= true;
1377 if(v
== m_endSource
) vSourceReached
= true;
1378 if(v
== m_endTarget
) vTargetReached
= true;
1380 // all targets reached?
1381 if (vEdgeReached
&& vSourceReached
&& vTargetReached
)
1383 paths
.m_pred
[pathToEdge
] = reconstructInsertionPath(m_endEdge
,
1384 paths
.m_src
[pathToEdge
], paths
.m_tgt
[pathToEdge
],
1385 paths
.m_paths
[pathToEdge
],
1386 paths
.m_addPartLeft
[pathToEdge
], paths
.m_addPartRight
[pathToEdge
],
1388 if(m_endSource
!= 0)
1389 paths
.m_pred
[pathToSource
] = reconstructInsertionPath(m_endSource
,
1390 paths
.m_src
[pathToSource
], paths
.m_tgt
[pathToSource
],
1391 paths
.m_paths
[pathToSource
],
1392 paths
.m_addPartLeft
[pathToSource
], paths
.m_addPartRight
[pathToSource
],
1394 if(m_endTarget
!= 0)
1395 paths
.m_pred
[pathToTarget
] = reconstructInsertionPath(m_endTarget
,
1396 paths
.m_src
[pathToTarget
], paths
.m_tgt
[pathToTarget
],
1397 paths
.m_paths
[pathToTarget
],
1398 paths
.m_addPartLeft
[pathToTarget
], paths
.m_addPartRight
[pathToTarget
],
1404 // append next candidate edges to queue
1405 // (all edges leaving v)
1407 forall_adj_edges(e
,v
) {
1408 if (v
!= e
->source()) continue;
1410 int listPos
= (currentDist
+ m_dualCost
[e
]) % maxCost
;
1411 nodesAtDist
[listPos
].pushBack(e
);
1416 int lenEdge
= paths
.m_paths
[pathToEdge
].size();
1417 int lenSrc
= paths
.m_paths
[pathToSource
].size();
1418 int lenTgt
= paths
.m_paths
[pathToTarget
].size();
1419 OGDF_ASSERT(m_endSource
== 0 || lenSrc
>= lenEdge
);
1420 OGDF_ASSERT(m_endTarget
== 0 || lenTgt
>= lenEdge
);
1422 //bPathToEdge = ((m_endSource == 0 || lenEdge <= lenSrc) && (m_endTarget == 0 || lenEdge <= lenTgt));
1424 bPathToSrc
= (m_endSource
!= 0 && lenSrc
== lenEdge
);
1425 bPathToTgt
= (m_endTarget
!= 0 && lenTgt
== lenEdge
);
1429 bool MMVariableEmbeddingInserter::dfsVertex(
1432 List
<Crossing
> &eip
,
1433 AnchorNodeInfo
&vStart
,
1434 AnchorNodeInfo
&vEnd
)
1436 // forall biconnected components containing v (except predecessor parent)
1437 SListConstIterator
<int> itI
;
1438 for(itI
= m_compV
[v
].begin(); itI
.valid(); ++itI
)
1442 if (i
== parent
) continue;
1444 node repS
; // representative of s in B(i)
1445 if (dfsBlock(i
,v
,repS
,eip
,vStart
,vEnd
) == true) { // path found?
1446 if(m_conFinished
) return true;
1448 // build graph BC of biconnected component B(i)
1452 SListConstIterator
<edge
> itE
;
1453 for(itE
= m_edgeB
[i
].begin(); itE
.valid(); ++itE
)
1457 node vSrc
= e
->source();
1458 if (m_GtoBC
[vSrc
] == 0) {
1459 BC
.m_vBCtoG
[m_GtoBC
[vSrc
] = BC
.newNode()] = vSrc
;
1460 nodesG
.pushBack(vSrc
);
1461 if(m_pSources
->isMember(vSrc
) || vSrc
== repS
)
1462 BC
.m_isSource
[m_GtoBC
[vSrc
]] = true;
1463 if(m_pTargets
->isMember(vSrc
) || vSrc
== v
)
1464 BC
.m_isTarget
[m_GtoBC
[vSrc
]] = true;
1465 BC
.m_isSplittable
[m_GtoBC
[vSrc
]] = m_pPG
->splittable(vSrc
);
1468 node vTgt
= e
->target();
1469 if (m_GtoBC
[vTgt
] == 0) {
1470 BC
.m_vBCtoG
[m_GtoBC
[vTgt
] = BC
.newNode()] = vTgt
;
1471 nodesG
.pushBack(vTgt
);
1472 if(m_pSources
->isMember(vTgt
) || vTgt
== repS
)
1473 BC
.m_isSource
[m_GtoBC
[vTgt
]] = true;
1474 if(m_pTargets
->isMember(vTgt
) || vTgt
== v
)
1475 BC
.m_isTarget
[m_GtoBC
[vTgt
]] = true;
1476 BC
.m_isSplittable
[m_GtoBC
[vTgt
]] = m_pPG
->splittable(vTgt
);
1479 edge eBC
= BC
.newEdge(m_GtoBC
[vSrc
],m_GtoBC
[vTgt
]);
1480 BC
.m_adjBCtoG
[eBC
->adjSource()] = e
->adjSource();
1481 BC
.m_adjBCtoG
[eBC
->adjTarget()] = e
->adjTarget();
1483 if(m_forbiddenEdgeOrig
!= 0) {
1484 edge eOrig
= m_pPG
->originalEdge(e
);
1486 BC
.m_forbidden
[eBC
] = (*m_forbiddenEdgeOrig
)[eOrig
];
1490 AnchorNodeInfo srcInfo
= repS
->firstAdj();
1491 AnchorNodeInfo tgtInfo
= v
->firstAdj();
1493 // less than 3 nodes requires no crossings (cannot build SPQR-tree
1494 // for a graph with less than 3 nodes!)
1495 if (nodesG
.size() >= 3) {
1496 // call biconnected case
1498 blockInsert(BC
, L
, srcInfo
, tgtInfo
);
1500 srcInfo
.m_adj_1
= BC
.m_adjBCtoG
[srcInfo
.m_adj_1
];
1501 if(srcInfo
.m_adj_2
!= 0)
1502 srcInfo
.m_adj_2
= BC
.m_adjBCtoG
[srcInfo
.m_adj_2
];
1503 tgtInfo
.m_adj_1
= BC
.m_adjBCtoG
[tgtInfo
.m_adj_1
];
1504 if(tgtInfo
.m_adj_2
!= 0)
1505 tgtInfo
.m_adj_2
= BC
.m_adjBCtoG
[tgtInfo
.m_adj_2
];
1507 // transform crossed edges to edges in G
1508 ListIterator
<Crossing
> it
;
1509 for(it
= L
.begin(); it
.valid(); ++it
) {
1511 if(cr
.m_adj
!= 0) cr
.m_adj
= BC
.m_adjBCtoG
[cr
.m_adj
];
1512 SListIterator
<adjEntry
> itAdj
;
1513 for(itAdj
= cr
.m_partitionLeft
.begin(); itAdj
.valid(); ++itAdj
)
1514 *itAdj
= BC
.m_adjBCtoG
[*itAdj
];
1515 for(itAdj
= cr
.m_partitionRight
.begin(); itAdj
.valid(); ++itAdj
)
1516 *itAdj
= BC
.m_adjBCtoG
[*itAdj
];
1518 //adjEntry adj1 = BC.m_BCtoG[(*it).m_adj1];
1519 //adjEntry adj2 = ((*it).m_adj1 == 0) ? 0 : BC.m_BCtoG[(*it).m_adj1];
1520 //eip.pushBack(Crossing(adj1,adj2));
1525 if(m_pSources
->isMember(srcInfo
.m_adj_1
->theNode()))
1528 if(m_pTargets
->isMember(tgtInfo
.m_adj_1
->theNode())) {
1530 m_conFinished
= true;
1533 // set entries of GtoBC back to nil (GtoBC allocated only once
1535 SListConstIterator
<node
> itV
;
1536 for(itV
= nodesG
.begin(); itV
.valid(); ++itV
)
1539 return true; // path found
1543 return false; // path not found
1547 bool MMVariableEmbeddingInserter::dfsBlock(int i
,
1550 List
<Crossing
> &eip
,
1551 AnchorNodeInfo
&vStart
,
1552 AnchorNodeInfo
&vEnd
)
1554 // forall nodes in biconected component B(i) (except predecessor parent)
1555 SListConstIterator
<node
> it
;
1556 for(it
= m_nodeB
[i
].begin(); it
.valid(); ++it
)
1560 if (repS
== parent
) continue;
1561 if (m_pSources
->isMember(repS
) == true) { // s found?
1565 if (dfsVertex(repS
,i
,eip
,vStart
,vEnd
) == true) {
1566 return true; // path found
1570 return false; // path not found
1574 //-------------------------------------------------------------------
1575 // find optimal edge insertion path for biconnected graph G
1576 //-------------------------------------------------------------------
1578 bool MMVariableEmbeddingInserter::pathSearch(
1584 if(BC
.containsTarget(v
) != 0)
1588 forall_adj_edges(e
,v
) {
1589 if(e
== parent
) continue;
1590 if(pathSearch(e
->opposite(v
),e
,BC
,path
) == true) {
1599 void MMVariableEmbeddingInserter::blockInsert(
1602 AnchorNodeInfo
&srcInfo
,
1603 AnchorNodeInfo
&tgtInfo
)
1606 srcInfo
= tgtInfo
= AnchorNodeInfo();
1608 // construct SPQR-tree
1609 BC
.m_pT
= new StaticPlanarSPQRTree(BC
);
1610 const StaticSPQRTree
&T
= *BC
.m_pT
;
1611 const Graph
&tree
= T
.tree();
1613 node v
, v1
= 0, vx
= 0;
1614 forall_nodes(v
,tree
) {
1615 if(BC
.containsSource(v
) != 0) {
1618 if(T
.typeOf(v
) == SPQRTree::RNode
&& BC
.containsTarget(v
) != 0) {
1626 // find path in tree connecting a nodes whose skeleton contains and
1627 // source and a target, resp.
1628 pathSearch(v1
,0,BC
,path
);
1630 // remove unnecessary allocation nodes of sources from start of path
1631 while(!path
.empty() && BC
.containsSource(v
= path
.front()->opposite(v1
)) != 0)
1639 // call build_subpath for every R-node building the list of crossed edges/nodes
1640 ExpandedSkeleton
exp(BC
);
1642 bool bPathToEdge
= true;
1643 bool bPathToSrc
= false;
1644 bool bPathToTgt
= false;
1645 Array
<Paths
> pathsInSks(path
.size()+1);
1648 switch(T
.typeOf(v1
)) {
1649 case SPQRTree::RNode
:
1651 (path
.empty()) ? 0 : path
.front(),
1659 case SPQRTree::PNode
:
1662 case SPQRTree::SNode
:
1663 srcInfo
.m_adj_1
= BC
.containsSourceAdj(v1
);
1668 ListConstIterator
<edge
> it
;
1669 for(it
= path
.begin(); it
.valid(); ++it
)
1674 switch(T
.typeOf(v
)) {
1675 case SPQRTree::RNode
:
1677 (it
.succ().valid() == false) ? 0 : *(it
.succ()),
1685 case SPQRTree::PNode
:
1688 case SPQRTree::SNode
:
1689 if(it
.succ().valid()) {
1690 edge eNext
= *it
.succ();
1692 edge e_1
= (v
== e
->target()) ? T
.skeletonEdgeTgt(e
) : T
.skeletonEdgeSrc(e
);
1693 edge e_2
= (v
== eNext
->target()) ? T
.skeletonEdgeTgt(eNext
) : T
.skeletonEdgeSrc(eNext
);
1695 bool bPathToSrcOld
= bPathToSrc
;
1696 bool bPathToTgtOld
= bPathToTgt
;
1698 Paths
&p
= pathsInSks
[i
];
1699 if(e_2
->source() == e_1
->source() && bPathToSrcOld
) {
1700 p
.m_pred
[pathToSource
] = pathToSource
;
1702 } else if (e_2
->source() == e_1
->target() && bPathToTgtOld
) {
1703 p
.m_pred
[pathToSource
] = pathToTarget
;
1708 if(e_2
->target() == e_1
->target() && bPathToTgtOld
) {
1709 p
.m_pred
[pathToTarget
] = pathToTarget
;
1711 } else if (e_2
->target() == e_1
->source() && bPathToSrcOld
) {
1712 p
.m_pred
[pathToTarget
] = pathToSource
;
1723 if(T
.typeOf(v
) == SPQRTree::SNode
)
1724 tgtInfo
.m_adj_1
= BC
.containsTargetAdj(v
);
1725 //tgtInfo.m_adj_1 = BC.containsTarget(v)->firstAdj();
1729 // construct list of crossings L
1730 int currentPath
= pathToEdge
;
1731 AnchorNodeInfo
&x
= pathsInSks
[i
-1].m_tgt
[currentPath
];
1734 SList
<adjEntry
> *pAddLeft
= 0;
1735 SList
<adjEntry
> *pAddRight
= 0;
1738 List
<Crossing
> &eip
= pathsInSks
[i
].m_paths
[currentPath
];
1740 if(currentPath
> 0) {
1742 pathsInSks
[i
].m_addPartLeft
[currentPath
].conc(*pAddLeft
);
1743 pathsInSks
[i
].m_addPartRight
[currentPath
].conc(*pAddRight
);
1746 Crossing
&cr
= *eip
.rbegin();
1747 cr
.m_partitionLeft
.conc(*pAddLeft
);
1748 cr
.m_partitionRight
.conc(*pAddRight
);
1754 pAddLeft
= &pathsInSks
[i
].m_addPartLeft
[currentPath
];
1755 pAddRight
= &pathsInSks
[i
].m_addPartRight
[currentPath
];
1757 AnchorNodeInfo
&x
= pathsInSks
[0].m_src
[currentPath
];
1760 OGDF_ASSERT(srcInfo
.m_adj_1
!= 0);
1763 currentPath
= pathsInSks
[i
].m_pred
[currentPath
];
1768 //-------------------------------------------------------------------
1769 // find the shortest path from represent. of s to represent. of t in
1770 // the dual of the (partially) expanded skeleton of v
1771 //-------------------------------------------------------------------
1773 void MMVariableEmbeddingInserter::buildSubpath(
1781 ExpandedSkeleton
&Exp
)
1783 // build expanded graph Exp
1784 Exp
.expand(v
,eIn
,eOut
);
1786 // construct augmented dual of expanded graph
1787 Exp
.constructDual(bPathToEdge
,bPathToSrc
,bPathToTgt
);
1789 // find shortest path in augmented dual
1790 Exp
.findShortestPath(bPathToEdge
, bPathToSrc
, bPathToTgt
, paths
);
1794 void MMVariableEmbeddingInserter::contractSplitIfReq(node u
)
1796 if(u
->degree() == 2) {
1797 edge eContract
= u
->firstAdj()->theEdge();
1798 edge eExpand
= u
->lastAdj ()->theEdge();
1799 if(m_pPG
->nodeSplitOf(eContract
) == 0)
1800 swap(eContract
,eExpand
);
1802 if(m_pPG
->nodeSplitOf(eContract
) != 0) {
1803 edge e
= m_pPG
->unsplitExpandNode(u
,eContract
,eExpand
);
1806 m_pPG
->removeSelfLoop(e
);
1812 void MMVariableEmbeddingInserter::convertDummy(
1815 PlanRepExpansion::nodeSplit ns_0
)
1817 PlanRepExpansion::nodeSplit ns_1
= m_pPG
->convertDummy(u
,vOrig
,ns_0
);
1819 if(ns_0
->m_path
.size() == 1)
1820 m_pPG
->contractSplit(ns_0
);
1821 if(ns_1
->m_path
.size() == 1)
1822 m_pPG
->contractSplit(ns_1
);
1826 void MMVariableEmbeddingInserter::collectAnchorNodes(
1829 const PlanRepExpansion::NodeSplit
*nsParent
) const
1831 if(m_pPG
->original(v
) != 0)
1836 edge e
= adj
->theEdge();
1837 const PlanRepExpansion::NodeSplit
*ns
= m_pPG
->nodeSplitOf(e
);
1839 // add dummy nodes of non-node-split edge
1840 ListConstIterator
<edge
> it
= m_pPG
->chain(m_pPG
->originalEdge(e
)).begin();
1841 for(++it
; it
.valid(); ++it
)
1842 nodes
.insert((*it
)->source());
1844 } else if(ns
!= nsParent
) {
1845 // add dummy nodes of node-split edge
1846 ListConstIterator
<edge
> it
= ns
->m_path
.begin();
1847 for(++it
; it
.valid(); ++it
)
1848 nodes
.insert((*it
)->source());
1850 node w
= (v
== e
->source()) ? ns
->target() : ns
->source();
1851 collectAnchorNodes(w
, nodes
, ns
);
1857 void MMVariableEmbeddingInserter::findSourcesAndTargets(
1860 NodeSet
&targets
) const
1862 collectAnchorNodes(src
, sources
, 0);
1863 collectAnchorNodes(tgt
, targets
, 0);
1867 void MMVariableEmbeddingInserter::anchorNodes(
1869 NodeSet
&nodes
) const
1871 node vFirst
= m_pPG
->expansion(vOrig
).front();
1872 if(m_pPG
->splittableOrig(vOrig
) == true)
1873 collectAnchorNodes(vFirst
, nodes
, 0);
1875 nodes
.insert(vFirst
);
1879 node
MMVariableEmbeddingInserter::commonDummy(
1883 ListConstIterator
<node
> it
;
1884 for(it
= sources
.nodes().begin(); it
.valid(); ++it
)
1885 if(targets
.isMember(*it
))
1893 } // end namespace ogdf