6 * $Date: 2012-07-15 22:39:24 +0200 (So, 15. Jul 2012) $
7 ***************************************************************/
10 * \brief Implementation of class VariableEmbeddingInserter2
12 * \author Carsten Gutwenger<br>Jan Papenfuß
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/VariableEmbeddingInserter2.h>
45 #include <ogdf/decomposition/DynamicSPQRForest.h>
46 #include <ogdf/basic/extended_graph_alg.h>
51 //---------------------------------------------------------
53 //---------------------------------------------------------
55 class BCandSPQRtrees
{
60 DynamicSPQRForest m_dynamicSPQRForest
;
62 bool m_forbidCrossingGens
;
63 const EdgeArray
<int>* m_costOrig
;
64 EdgeArray
<int> m_cost
;
65 EdgeArray
<Graph::EdgeType
> m_typeOf
;
69 BCandSPQRtrees (PlanRep
* pPG
, bool forbidCrossingGens
, const EdgeArray
<int>* costOrig
);
70 DynamicSPQRForest
& dynamicSPQRForest () { return m_dynamicSPQRForest
; }
71 void insertEdgePath (edge eOrig
, const SList
<adjEntry
>& crossedEdges
);
73 void cost (edge e
, int c
) { m_cost
[e
] = c
; }
74 int cost (edge e
) const { return m_cost
[e
]; }
75 void typeOf (edge e
, Graph::EdgeType et
) { m_typeOf
[e
] = et
; }
76 Graph::EdgeType
typeOf (edge e
) const { return m_typeOf
[e
]; }
80 BCandSPQRtrees::BCandSPQRtrees (PlanRep
* pPG
, bool forbidCrossingGens
, const EdgeArray
<int>* costOrig
) : m_pPG(pPG
), m_dynamicSPQRForest(*pPG
), m_forbidCrossingGens(forbidCrossingGens
), m_costOrig(costOrig
)
82 const Graph
& H
= m_dynamicSPQRForest
.auxiliaryGraph();
87 edge e
= m_dynamicSPQRForest
.original(f
);
88 m_typeOf
[f
] = m_forbidCrossingGens
? m_pPG
->typeOf(e
) : Graph::association
;
90 edge eOrig
= m_pPG
->original(e
);
91 m_cost
[f
] = eOrig
? (*m_costOrig
)[eOrig
] : 0;
97 void BCandSPQRtrees::insertEdgePath (edge eOrig
, const SList
<adjEntry
>& crossedEdges
)
101 SListConstIterator
<adjEntry
> kt
;
102 for (kt
=crossedEdges
.begin(); kt
.valid(); ++kt
) {
103 ti
.pushBack((*kt
)->theEdge());
104 tj
.pushBack((*kt
)->theEdge()->target());
107 m_pPG
->insertEdgePath(eOrig
,crossedEdges
);
109 Graph::EdgeType typeOfEOrig
= m_forbidCrossingGens
? m_pPG
->typeOrig(eOrig
) : Graph::association
;
110 int costOfEOrig
= m_costOrig
? eOrig
? (*m_costOrig
)[eOrig
] : 0 : 1;
112 node v
= m_pPG
->copy(eOrig
->source());
113 SListConstIterator
<edge
> it
= ti
.begin();
114 SListConstIterator
<node
> jt
= tj
.begin();
115 for (kt
=crossedEdges
.begin(); it
.valid(); ++it
, ++jt
, ++kt
) {
117 node u
= e
->target();
119 for (a
=u
->firstAdj(); a
->theEdge()->target()!=*jt
; a
=a
->succ());
120 edge f
= a
->theEdge();
121 m_dynamicSPQRForest
.updateInsertedNode(e
,f
);
122 e
= m_dynamicSPQRForest
.rep(e
);
123 f
= m_dynamicSPQRForest
.rep(f
);
124 m_typeOf
[f
] = m_typeOf
[e
];
125 m_cost
[f
] = m_cost
[e
];
126 for (a
=u
->firstAdj(); a
->theEdge()->source()!=v
; a
=a
->succ());
128 m_dynamicSPQRForest
.updateInsertedEdge(f
);
129 f
= m_dynamicSPQRForest
.rep(f
);
130 m_typeOf
[f
] = typeOfEOrig
;
131 m_cost
[f
] = costOfEOrig
;
134 node u
= m_pPG
->copy(eOrig
->target());
136 for (a
=v
->firstAdj(); a
->theEdge()->target()!=u
; a
=a
->succ());
137 edge f
= a
->theEdge();
138 m_dynamicSPQRForest
.updateInsertedEdge(f
);
139 f
= m_dynamicSPQRForest
.rep(f
);
140 m_typeOf
[f
] = typeOfEOrig
;
141 m_cost
[f
] = costOfEOrig
;
146 //-------------------------------------------------------------------
147 // ExpandedGraph2 represents the (partially) expanded graph with
148 // its augmented dual
149 //-------------------------------------------------------------------
153 BCandSPQRtrees
&m_BC
;
155 NodeArray
<node
> m_GtoExp
;
157 Graph m_exp
; // expanded graph
158 ConstCombinatorialEmbedding m_E
;
159 AdjEntryArray
<adjEntry
> m_expToG
;
160 edge m_eS
, m_eT
; // (virtual) edges in exp representing s and t (if any)
162 Graph m_dual
; // augmented dual graph of exp
163 EdgeArray
<adjEntry
> m_primalEdge
;
164 EdgeArray
<bool> m_primalIsGen
; // true iff corresponding primal edge is a generalization
166 node m_vS
, m_vT
; // augmented nodes in dual representing s and t
169 ExpandedGraph2(BCandSPQRtrees
&BC
);
171 void expand(node v
, node vPred
, node vSucc
);
173 void constructDual(node s
, node t
, GraphCopy
&GC
, const EdgeArray
<bool> *forbiddenEdgeOrig
);
174 void constructDualForbidCrossingGens(node s
, node t
);
176 void findShortestPath(Graph::EdgeType eType
, List
<adjEntry
> &L
);
177 void findWeightedShortestPath(Graph::EdgeType eType
,
180 int costDual(edge eDual
) const {
181 adjEntry adjExp
= m_primalEdge
[eDual
];
182 return (adjExp
== 0) ? 0 : m_BC
.cost(m_expToG
[adjExp
]->theEdge());
185 // avoid automatic creation of assignment operator
186 ExpandedGraph2
&operator=(const ExpandedGraph2
&);
189 edge
insertEdge(node vG
, node wG
, edge eG
);
190 void expandSkeleton(node v
, edge e1
, edge e2
);
194 ExpandedGraph2::ExpandedGraph2(BCandSPQRtrees
&BC
) : m_BC(BC
),
195 m_GtoExp(BC
.dynamicSPQRForest().auxiliaryGraph(),0), m_expToG(m_exp
,0),
196 m_primalEdge(m_dual
,0), m_primalIsGen(m_dual
,false)
201 //-------------------------------------------------------------------
202 // build expanded graph (by expanding skeleton(v), nodes vPred and
203 // vSucc are the predecessor and successor tree nodes of v on the
204 // path from v1 to v2
205 //-------------------------------------------------------------------
207 void ExpandedGraph2::expand(node v
, node vPred
, node vSucc
)
210 while (!m_nodesG
.empty())
211 m_GtoExp
[m_nodesG
.popBackRet()] = 0;
215 eInS
= m_BC
.dynamicSPQRForest().virtualEdge(vPred
,v
);
216 m_eS
= insertEdge(eInS
->source(),eInS
->target(),0);
220 eOutS
= m_BC
.dynamicSPQRForest().virtualEdge(vSucc
,v
);
221 m_eT
= insertEdge(eOutS
->source(),eOutS
->target(),0);
224 expandSkeleton(v
, eInS
, eOutS
);
231 //-------------------------------------------------------------------
232 // expand one skeleton (recursive construction)
233 //-------------------------------------------------------------------
235 void ExpandedGraph2::expandSkeleton(node v
, edge e1
, edge e2
)
237 ListConstIterator
<edge
> i
;
238 for(i
= m_BC
.dynamicSPQRForest().hEdgesSPQR(v
).begin(); i
.valid(); ++i
)
240 edge et
= m_BC
.dynamicSPQRForest().twinEdge(*i
);
242 if (et
== 0) insertEdge((*i
)->source(),(*i
)->target(),*i
);
244 // do not expand virtual edges corresponding to tree edges e1 or e2
245 else if (*i
!= e1
&& *i
!= e2
)
246 expandSkeleton(m_BC
.dynamicSPQRForest().spqrproper(et
),et
,0);
251 //-------------------------------------------------------------------
252 // insert edge in exp (from a node corresponding to vG in G to a node
253 // corresponding to wG)
254 //-------------------------------------------------------------------
256 edge
ExpandedGraph2::insertEdge(node vG
, node wG
, edge eG
)
258 node
&rVG
= m_GtoExp
[vG
];
259 node
&rWG
= m_GtoExp
[wG
];
262 rVG
= m_exp
.newNode();
263 m_nodesG
.pushBack(vG
);
266 rWG
= m_exp
.newNode();
267 m_nodesG
.pushBack(wG
);
270 edge e1
= m_exp
.newEdge(rVG
,rWG
);
273 m_expToG
[e1
->adjSource()] = eG
->adjSource();
274 m_expToG
[e1
->adjTarget()] = eG
->adjTarget();
276 m_expToG
[e1
->adjSource()] = 0;
277 m_expToG
[e1
->adjTarget()] = 0;
284 //-------------------------------------------------------------------
285 // construct augmented dual of exp
286 //-------------------------------------------------------------------
288 void ExpandedGraph2::constructDual(node s
, node t
,
289 GraphCopy
&GC
, const EdgeArray
<bool> *forbiddenEdgeOrig
)
293 FaceArray
<node
> faceNode(m_E
);
295 // constructs nodes (for faces in exp)
297 forall_faces(f
,m_E
) {
298 faceNode
[f
] = m_dual
.newNode();
301 // construct dual edges (for primal edges in exp)
303 forall_nodes(v
,m_exp
)
308 // cannot cross edges that does not correspond to real edges
309 adjEntry adjG
= m_expToG
[adj
];
313 // Do not insert edges into dual if crossing the original edge
315 if(forbiddenEdgeOrig
&&
316 (*forbiddenEdgeOrig
)[GC
.original(m_BC
.dynamicSPQRForest().original(m_expToG
[adj
]->theEdge()))] == true)
319 node vLeft
= faceNode
[m_E
.leftFace (adj
)];
320 node vRight
= faceNode
[m_E
.rightFace(adj
)];
322 m_primalEdge
[m_dual
.newEdge(vLeft
,vRight
)] = adj
;
326 // augment dual by m_vS and m_vT
327 m_vS
= m_dual
.newNode();
328 if (m_GtoExp
[s
] != 0)
331 forall_adj(adj
,m_GtoExp
[s
])
332 m_dual
.newEdge(m_vS
,faceNode
[m_E
.rightFace(adj
)]);
336 m_dual
.newEdge(m_vS
,faceNode
[m_E
.rightFace(m_eS
->adjSource())]);
337 m_dual
.newEdge(m_vS
,faceNode
[m_E
.rightFace(m_eS
->adjTarget())]);
340 m_vT
= m_dual
.newNode();
341 if (m_GtoExp
[t
] != 0)
344 forall_adj(adj
,m_GtoExp
[t
])
345 m_dual
.newEdge(faceNode
[m_E
.rightFace(adj
)], m_vT
);
349 m_dual
.newEdge(faceNode
[m_E
.rightFace(m_eT
->adjSource())], m_vT
);
350 m_dual
.newEdge(faceNode
[m_E
.rightFace(m_eT
->adjTarget())], m_vT
);
355 void ExpandedGraph2::constructDualForbidCrossingGens(node s
, node t
)
359 FaceArray
<node
> faceNode(m_E
);
361 // constructs nodes (for faces in exp)
363 forall_faces(f
,m_E
) {
364 faceNode
[f
] = m_dual
.newNode();
368 // construct dual edges (for primal edges in exp)
370 forall_nodes(v
,m_exp
)
375 // cannot cross edges that does not correspond to real edges
376 adjEntry adjG
= m_expToG
[adj
];
380 node vLeft
= faceNode
[m_E
.leftFace (adj
)];
381 node vRight
= faceNode
[m_E
.rightFace(adj
)];
383 edge e
= m_dual
.newEdge(vLeft
,vRight
);
384 m_primalEdge
[e
] = adj
;
386 // mark dual edges corresponding to generalizations
387 if (adjG
&& m_BC
.typeOf(adjG
->theEdge()) == Graph::generalization
)
388 m_primalIsGen
[e
] = true;
390 OGDF_ASSERT(m_primalEdge
[e
] == 0 || m_expToG
[m_primalEdge
[e
]] != 0);
394 // augment dual by m_vS and m_vT
395 m_vS
= m_dual
.newNode();
396 if (m_GtoExp
[s
] != 0)
399 forall_adj(adj
,m_GtoExp
[s
]) {
400 eDual
= m_dual
.newEdge(m_vS
,faceNode
[m_E
.rightFace(adj
)]);
401 OGDF_ASSERT(m_primalEdge
[eDual
] == 0 || m_expToG
[m_primalEdge
[eDual
]] != 0);
406 eDual
= m_dual
.newEdge(m_vS
,faceNode
[m_E
.rightFace(m_eS
->adjSource())]);
407 OGDF_ASSERT(m_primalEdge
[eDual
] == 0 || m_expToG
[m_primalEdge
[eDual
]] != 0);
409 eDual
= m_dual
.newEdge(m_vS
,faceNode
[m_E
.rightFace(m_eS
->adjTarget())]);
410 OGDF_ASSERT(m_primalEdge
[eDual
] == 0 || m_expToG
[m_primalEdge
[eDual
]] != 0);
413 m_vT
= m_dual
.newNode();
414 if (m_GtoExp
[t
] != 0)
417 forall_adj(adj
,m_GtoExp
[t
]) {
418 eDual
= m_dual
.newEdge(faceNode
[m_E
.rightFace(adj
)], m_vT
);
419 OGDF_ASSERT(m_primalEdge
[eDual
] == 0 || m_expToG
[m_primalEdge
[eDual
]] != 0);
424 eDual
= m_dual
.newEdge(faceNode
[m_E
.rightFace(m_eT
->adjSource())], m_vT
);
425 OGDF_ASSERT(m_primalEdge
[eDual
] == 0 || m_expToG
[m_primalEdge
[eDual
]] != 0);
427 eDual
= m_dual
.newEdge(faceNode
[m_E
.rightFace(m_eT
->adjTarget())], m_vT
);
428 OGDF_ASSERT(m_primalEdge
[eDual
] == 0 || m_expToG
[m_primalEdge
[eDual
]] != 0);
433 //-------------------------------------------------------------------
434 // find shortest path in dual from m_vS to m_vT; output this path
435 // in L by omitting first and last edge, and translating edges to G
436 //-------------------------------------------------------------------
438 void ExpandedGraph2::findShortestPath(Graph::EdgeType eType
, List
<adjEntry
> &L
)
440 NodeArray
<edge
> spPred(m_dual
,0); // predecessor in shortest path tree
441 List
<edge
> queue
; // candidate edges
443 // start with all edges leaving from m_vS
445 forall_adj_edges(e
,m_vS
)
449 edge eCand
= queue
.popFrontRet(); // next candidate from front of queue
450 node v
= eCand
->target();
452 // hit an unvisited node ?
453 if (spPred
[v
] == 0) {
456 // if it is m_vT, we have found the shortest path
458 // build path from shortest path tree
460 adjEntry adjExp
= m_primalEdge
[spPred
[v
]];
461 if (adjExp
!= 0) // == nil for first and last edge
462 L
.pushFront(m_expToG
[adjExp
]);
463 v
= spPred
[v
]->source();
468 // append next candidates to end of queue
469 forall_adj_edges(e
,v
) {
470 if(v
== e
->source() &&
471 (eType
!= Graph::generalization
|| m_primalIsGen
[e
] == false))
481 //-------------------------------------------------------------------
482 // find weighted shortest path in dual from m_vS to m_vT; output this path
483 // in L by omitting first and last edge, and translating edges to G
484 //-------------------------------------------------------------------
486 void ExpandedGraph2::findWeightedShortestPath(Graph::EdgeType eType
,
491 forall_edges(eDual
,m_dual
) {
492 int c
= costDual(eDual
);
493 if (c
> maxCost
) maxCost
= c
;
497 Array
<SListPure
<edge
> > nodesAtDist(maxCost
);
499 NodeArray
<edge
> spPred(m_dual
,0); // predecessor in shortest path tree
500 //List<edge> queue; // candidate edges
502 // start with all edges leaving from m_vS
504 forall_adj_edges(e
,m_vS
)
505 nodesAtDist
[0].pushBack(e
);
507 // actual search (using extended bfs on directed dual)
510 // next candidate edge
511 while(nodesAtDist
[currentDist
% maxCost
].empty())
514 edge eCand
= nodesAtDist
[currentDist
% maxCost
].popFrontRet();
515 node v
= eCand
->target();
517 // leads to an unvisited node ?
518 if (spPred
[v
] == 0) {
519 // yes, then we set v's predecessor in search tree
522 // have we reached t ...
524 // ... then search is done.
525 // construct list of used edges (translated to crossed
526 // adjacency entries in G)
528 adjEntry adjExp
= m_primalEdge
[spPred
[v
]];
529 if (adjExp
!= 0) // == nil for first and last edge
530 L
.pushFront(m_expToG
[adjExp
]);
531 v
= spPred
[v
]->source();
536 // append next candidates to end of queue
537 // (all edges leaving v)
538 forall_adj_edges(e
,v
) {
539 if(v
== e
->source() &&
540 (eType
!= Graph::generalization
|| m_primalIsGen
[e
] == false))
542 int listPos
= (currentDist
+ costDual(e
)) % maxCost
;
543 nodesAtDist
[listPos
].pushBack(e
);
552 //---------------------------------------------------------
553 // VEICrossingsBucket
554 // bucket function for sorting edges by decreasing number
556 //---------------------------------------------------------
558 class VEICrossingsBucket
: public BucketFunc
<edge
>
560 const PlanRep
*m_pPG
;
563 VEICrossingsBucket(const PlanRep
*pPG
) :
566 int getBucket(const edge
&e
) {
567 return -m_pPG
->chain(e
).size();
573 //---------------------------------------------------------
574 // VariableEmbeddingInserter2
575 //---------------------------------------------------------
577 //---------------------------------------------------------
579 // sets default values for options
581 VariableEmbeddingInserter2::VariableEmbeddingInserter2()
584 m_percentMostCrossed
= 25;
588 //---------------------------------------------------------
589 // actual call (called by all variations of call)
590 // crossing of generalizations is forbidden if forbidCrossingGens = true
591 // edge costs are obeyed if costOrig != 0
593 Module::ReturnType
VariableEmbeddingInserter2::doCall(
595 const List
<edge
> &origEdges
,
596 bool forbidCrossingGens
,
597 const EdgeArray
<int> *costOrig
,
598 const EdgeArray
<bool> *forbiddenEdgeOrig
)
603 ReturnType retValue
= retFeasible
;
604 m_runsPostprocessing
= 0;
606 if (origEdges
.size() == 0)
607 return retOptimal
; // nothing to do
609 OGDF_ASSERT(forbidCrossingGens
== false || forbiddenEdgeOrig
== 0);
612 m_forbidCrossingGens
= forbidCrossingGens
;
613 m_costOrig
= costOrig
;
614 m_forbiddenEdgeOrig
= forbiddenEdgeOrig
;
616 SListPure
<edge
> currentOrigEdges
;
617 ListConstIterator
<edge
> it
;
619 if(removeReinsert() == rrIncremental
) {
622 currentOrigEdges
.pushBack(PG
.original(e
));
624 // insertion of edges
625 for(it
= origEdges
.begin(); it
.valid(); ++it
)
628 m_typeOfCurrentEdge
= m_forbidCrossingGens
? PG
.typeOrig(eOrig
) : Graph::association
;
630 m_pBC
= new BCandSPQRtrees(m_pPG
,m_forbidCrossingGens
,m_costOrig
);
633 PG
.insertEdgePath(eOrig
,eip
);
636 currentOrigEdges
.pushBack(eOrig
);
640 ++m_runsPostprocessing
;
643 SListConstIterator
<edge
> itRR
;
644 for(itRR
= currentOrigEdges
.begin(); itRR
.valid(); ++itRR
)
646 edge eOrigRR
= *itRR
;
650 pathLength
= costCrossed(eOrigRR
);
652 pathLength
= PG
.chain(eOrigRR
).size() - 1;
653 if (pathLength
== 0) continue; // cannot improve
655 PG
.removeEdgePath(eOrigRR
);
657 m_typeOfCurrentEdge
= m_forbidCrossingGens
? PG
.typeOrig(eOrigRR
) : Graph::association
;
659 m_pBC
= new BCandSPQRtrees(m_pPG
,m_forbidCrossingGens
,m_costOrig
);
662 PG
.insertEdgePath(eOrigRR
,eip
);
665 int newPathLength
= (costOrig
!= 0) ? costCrossed(eOrigRR
) : (PG
.chain(eOrigRR
).size() - 1);
666 OGDF_ASSERT(newPathLength
<= pathLength
);
668 if(newPathLength
< pathLength
)
675 // insertion of edges
676 m_pBC
= new BCandSPQRtrees(m_pPG
,m_forbidCrossingGens
,m_costOrig
);
677 for(it
= origEdges
.begin(); it
.valid(); ++it
)
680 m_typeOfCurrentEdge
= m_forbidCrossingGens
? PG
.typeOrig(eOrig
) : Graph::association
;
684 m_pBC
->insertEdgePath(eOrig
,eip
);
688 // postprocessing (remove-reinsert heuristc)
689 const Graph
&G
= PG
.original();
690 SListPure
<edge
> rrEdges
;
692 switch(removeReinsert())
695 case rrMostCrossed
: {
696 const List
<node
> &origInCC
= PG
.nodesInCC();
697 ListConstIterator
<node
> itV
;
699 for(itV
= origInCC
.begin(); itV
.valid(); ++itV
) {
703 if ((adj
->index() & 1) == 0) continue;
704 edge eG
= adj
->theEdge();
705 rrEdges
.pushBack(eG
);
712 for(ListConstIterator
<edge
> it
= origEdges
.begin(); it
.valid(); ++it
)
713 rrEdges
.pushBack(*it
);
722 // marks the end of the interval of rrEdges over which we iterate
723 // initially set to invalid iterator which means all edges
724 SListConstIterator
<edge
> itStop
;
728 // abort postprocessing if time limit reached
729 if (m_timeLimit
>= 0 && m_timeLimit
<= usedTime(T
)) {
730 retValue
= retTimeoutFeasible
;
734 ++m_runsPostprocessing
;
737 if(removeReinsert() == rrMostCrossed
)
739 VEICrossingsBucket
bucket(&PG
);
740 rrEdges
.bucketSort(bucket
);
742 const int num
= int(0.01 * percentMostCrossed() * G
.numberOfEdges());
743 itStop
= rrEdges
.get(num
);
746 SListConstIterator
<edge
> it
;
747 for(it
= rrEdges
.begin(); it
!= itStop
; ++it
)
753 pathLength
= costCrossed(eOrig
);
755 pathLength
= PG
.chain(eOrig
).size() - 1;
756 if (pathLength
== 0) continue; // cannot improve
758 PG
.removeEdgePath(eOrig
);
760 m_typeOfCurrentEdge
= m_forbidCrossingGens
? PG
.typeOrig(eOrig
) : Graph::association
;
762 m_pBC
= new BCandSPQRtrees(m_pPG
,m_forbidCrossingGens
,m_costOrig
);
765 PG
.insertEdgePath(eOrig
,eip
);
768 // we cannot find a shortest path that is longer than before!
769 int newPathLength
= (costOrig
!= 0) ? costCrossed(eOrig
) : (PG
.chain(eOrig
).size() - 1);
770 OGDF_ASSERT(newPathLength
<= pathLength
);
772 if(newPathLength
< pathLength
)
783 OGDF_ASSERT(isPlanar
);
785 PG
.removePseudoCrossings();
786 OGDF_ASSERT(PG
.representsCombEmbedding());
787 OGDF_ASSERT(forbidCrossingGens
== false || checkCrossingGens(static_cast<const PlanRepUML
&>(PG
)) == true);
793 edge
VariableEmbeddingInserter2::crossedEdge(adjEntry adj
) const
795 edge e
= adj
->theEdge();
797 adj
= adj
->cyclicSucc();
798 while(adj
->theEdge() == e
)
799 adj
= adj
->cyclicSucc();
801 return adj
->theEdge();
805 int VariableEmbeddingInserter2::costCrossed(edge eOrig
) const
809 const List
<edge
> &L
= m_pPG
->chain(eOrig
);
811 ListConstIterator
<edge
> it
= L
.begin();
812 for(++it
; it
.valid(); ++it
) {
813 c
+= (*m_costOrig
)[m_pPG
->original(crossedEdge((*it
)->adjSource()))];
820 //-------------------------------------------------------------------
821 // find optimal edge insertion path from s to t in connected
823 //-------------------------------------------------------------------
825 void VariableEmbeddingInserter2::insert (edge eOrig
, SList
<adjEntry
>& eip
)
828 node s
= m_pPG
->copy(eOrig
->source());
829 node t
= m_pPG
->copy(eOrig
->target());
831 // find path from s to t in BC-tree
832 // call of blockInsert() is done when we have found the path
833 // if no path is found, s and t are in different connected components
834 // and thus an empty edge insertion path is correct!
835 DynamicSPQRForest
& dSPQRF
= m_pBC
->dynamicSPQRForest();
836 SList
<node
>& path
= dSPQRF
.findPath(s
,t
);
838 SListIterator
<node
> it
=path
.begin();
839 node repS
= dSPQRF
.repVertex(s
,*it
);
840 for (SListIterator
<node
> jt
=it
; it
.valid(); ++it
) {
841 node repT
= (++jt
).valid() ? dSPQRF
.cutVertex(*jt
,*it
) : dSPQRF
.repVertex(t
,*it
);
843 // less than 3 nodes requires no crossings (cannot build SPQR-tree
844 // for a graph with less than 3 nodes!)
845 if (dSPQRF
.numberOfNodes(*it
)>3) {
847 blockInsert(repS
,repT
,L
); // call biconnected case
849 // transform crossed edges to edges in G
850 for (ListConstIterator
<adjEntry
> kt
=L
.begin(); kt
.valid(); ++kt
) {
851 edge e
= (*kt
)->theEdge();
852 eip
.pushBack(e
->adjSource()==*kt
? dSPQRF
.original(e
)->adjSource()
853 : dSPQRF
.original(e
)->adjTarget());
856 if (jt
.valid()) repS
= dSPQRF
.cutVertex(*it
,*jt
);
863 //-------------------------------------------------------------------
864 // find optimal edge insertion path from s to t for biconnected
865 // graph G (OptimalBlockInserter)
866 //-------------------------------------------------------------------
868 void VariableEmbeddingInserter2::blockInsert(node s
, node t
, List
<adjEntry
> &L
)
872 // find path in SPQR-tree from an allocation node of s
873 // to an allocation node of t
874 SList
<node
>& path
= m_pBC
->dynamicSPQRForest().findPathSPQR(s
,t
);
876 // call build_subpath for every R-node building the list L of crossed edges
877 ExpandedGraph2
Exp(*m_pBC
);
881 SListConstIterator
<node
> it
;
882 for(it
= path
.begin(); *it
; ++it
)
885 node vSucc
= *it
.succ();
887 if (m_pBC
->dynamicSPQRForest().typeOfTNode(v
) == DynamicSPQRForest::RComp
)
888 buildSubpath(v
, vPred
, vSucc
, L
, Exp
, s
, t
);
897 //-------------------------------------------------------------------
898 // find the shortest path from represent. of s to represent. of t in
899 // the dual of the (partially) expanded skeleton of v
900 //-------------------------------------------------------------------
902 void VariableEmbeddingInserter2::buildSubpath(
911 // build expanded graph Exp
912 Exp
.expand(v
,vPred
,vSucc
);
914 // construct augmented dual of expanded graph
915 if(m_forbidCrossingGens
)
916 Exp
.constructDualForbidCrossingGens(s
,t
);
918 Exp
.constructDual(s
,t
,*m_pPG
,m_forbiddenEdgeOrig
);
920 // find shortest path in augmented dual
921 List
<adjEntry
> subpath
;
923 Exp
.findWeightedShortestPath(m_typeOfCurrentEdge
,subpath
);
925 Exp
.findShortestPath(m_typeOfCurrentEdge
,subpath
);
931 } // end namespace ogdf