6 * $Date: 2012-07-05 16:45:20 +0200 (Do, 05. Jul 2012) $
7 ***************************************************************/
10 * \brief Implements Hopcroft/Tarjan algorithm for finding the
11 * triconnected components of a biconnected multi-graph
13 * \author Carsten Gutwenger
16 * This file is part of the Open Graph Drawing Framework (OGDF).
20 * See README.txt in the root directory of the OGDF installation for details.
23 * This program is free software; you can redistribute it and/or
24 * modify it under the terms of the GNU General Public License
25 * Version 2 or 3 as published by the Free Software Foundation;
26 * see the file LICENSE.txt included in the packaging of this file
30 * This program is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 * GNU General Public License for more details.
36 * You should have received a copy of the GNU General Public
37 * License along with this program; if not, write to the Free
38 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
39 * Boston, MA 02110-1301, USA.
41 * \see http://www.gnu.org/copyleft/gpl.html
42 ***************************************************************/
46 #include <ogdf/basic/GraphCopy.h>
47 #include <ogdf/basic/simple_graph_alg.h>
48 #include <ogdf/basic/NodeSet.h>
50 //#define TRIC_COMP_OUTPUT
56 //----------------------------------------------------------
60 //----------------------------------------------------------
68 //----------------------------------------------------------
71 // Divides G into triconnected components.
72 //----------------------------------------------------------
74 TricComp::TricComp (const Graph
& G
) :
75 m_ESTACK(G
.numberOfEdges())
77 m_pGC
= new GraphCopySimple(G
);
78 GraphCopySimple
&GC
= *m_pGC
;
80 const int n
= GC
.numberOfNodes();
81 const int m
= GC
.numberOfEdges();
83 #ifdef TRIC_COMP_OUTPUT
84 cout
<< "Dividing G into triconnected components.\n" << endl
;
85 cout
<< "n = " << n
<< ", m = " << m
<< endl
<< endl
;
88 m_component
= Array
<CompStruct
>(3*m
-6);
93 OGDF_ASSERT_IF(dlExtendedChecking
, isBiconnected(G
));
97 CompStruct
&C
= newComp();
105 m_TYPE
.init(GC
,unseen
);
109 m_NUMBER
.init(GC
,0); m_LOWPT1
.init(GC
);
110 m_LOWPT2
.init(GC
); m_FATHER
.init(GC
,0);
111 m_ND
.init(GC
); m_DEGREE
.init(GC
);
112 m_TREE_ARC
.init(GC
,0);
113 m_NODEAT
= Array
<node
>(1,n
);
116 m_start
= GC
.firstNode();
121 bool up
= (m_NUMBER
[e
->target()] - m_NUMBER
[e
->source()] > 0);
122 if ((up
&& m_TYPE
[e
] == frond
) || (!up
&& m_TYPE
[e
] == tree
))
126 #ifdef TRIC_COMP_OUTPUT
127 cout
<< "\nnode\tNUMBER\tFATHER\tLOWPT1\tLOWPT2\tND" << endl
;
130 cout
<< GC
.original(v
) << ": \t" << m_NUMBER
[v
] << " \t";
131 if (m_FATHER
[v
] == 0) cout
<< "nil \t";
132 else cout
<< GC
.original(m_FATHER
[v
]) << " \t";
133 cout
<< m_LOWPT1
[v
] << " \t" << m_LOWPT2
[v
] << " \t" << m_ND
[v
] << endl
;
139 buildAcceptableAdjStruct(GC
);
141 #ifdef TRIC_COMP_OUTPUT
142 cout
<< "\nadjaceny lists:" << endl
;
145 ListConstIterator
<edge
> itE
;
146 for(itE
= m_A
[v
].begin(); itE
.valid(); ++itE
) {
155 #ifdef TRIC_COMP_OUTPUT
156 cout
<< "\nnode\tNEWNUM\tLOWPT1\tLOWPT2\tHIGHPT" << endl
;
158 cout
<< GC
.original(v
) << ": \t" << m_NEWNUM
[v
] << " \t";
159 cout
<< m_LOWPT1
[v
] << " \t" << m_LOWPT2
[v
] << " \t";
160 ListConstIterator
<int> itH
;
161 for(itH
= m_HIGHPT
[v
].begin(); itH
.valid(); ++itH
)
166 cout
<< "\nedges starting a path:" << endl
;
175 m_TSTACK_h
= new int[2*m
+1];
176 m_TSTACK_a
= new int[2*m
+1];
177 m_TSTACK_b
= new int[2*m
+1];
178 m_TSTACK_a
[m_top
= 0] = -1; // start with EOS
180 pathSearch(G
,m_start
);
182 // last split component
183 CompStruct
&C
= newComp();
184 while(!m_ESTACK
.empty()) {
187 C
.m_type
= (C
.m_edges
.size() > 4) ? triconnected
: polygon
;
189 #ifdef TRIC_COMP_OUTPUT
193 delete [] m_TSTACK_h
;
194 delete [] m_TSTACK_a
;
195 delete [] m_TSTACK_b
;
198 m_NUMBER
.init(); m_LOWPT1
.init();
199 m_LOWPT2
.init(); m_FATHER
.init();
200 m_ND
.init(); m_TYPE
.init();
201 m_A
.init(); m_NEWNUM
.init();
202 m_HIGHPT
.init(); m_START
.init();
203 m_DEGREE
.init(); m_TREE_ARC
.init();
204 m_IN_ADJ
.init(); m_IN_HIGH
.init();
208 assembleTriconnectedComponents();
210 // Caution: checkComp() assumes that the graph is simple!
211 //OGDF_ASSERT(checkComp());
213 #ifdef TRIC_COMP_OUTPUT
214 cout
<< "\n\nTriconnected components:\n";
215 for (int i
= 0; i
< m_numComp
; i
++) {
216 const List
<edge
> &L
= m_component
[i
].m_edges
;
217 if (L
.size() == 0) continue;
218 cout
<< "[" << i
<< "] ";
219 switch(m_component
[i
].m_type
) {
220 case bond
: cout
<< "bond "; break;
221 case polygon
: cout
<< "polygon "; break;
222 case triconnected
: cout
<< "triconnected "; break;
225 ListConstIterator
<edge
> itE
;
226 for(itE
= L
.begin(); itE
.valid(); ++itE
)
234 //----------------------------------------------------------
237 // Tests G for triconnectivity and returns a cut vertex in
238 // s1 or a separation pair in (s1,s2).
239 //----------------------------------------------------------
241 TricComp::TricComp(const Graph
&G
, bool &isTric
, node
&s1
, node
&s2
)
243 m_pGC
= new GraphCopySimple(G
);
244 GraphCopySimple
&GC
= *m_pGC
;
246 const int n
= GC
.numberOfNodes();
247 const int m
= GC
.numberOfEdges();
252 isTric
= true; return;
256 makeParallelFreeUndirected(GC
);
259 m_TYPE
.init(GC
,unseen
);
260 m_NUMBER
.init(GC
,0); m_LOWPT1
.init(GC
);
261 m_LOWPT2
.init(GC
); m_FATHER
.init(GC
,0);
262 m_ND
.init(GC
); m_DEGREE
.init(GC
);
265 m_TREE_ARC
.init(GC
,0); // probably not required
268 m_start
= GC
.firstNode();
269 DFS1(GC
,m_start
,0,s1
);
271 // graph not even connected?
273 s1
= 0; isTric
= false;
277 // graph no biconnected?
279 s1
= GC
.original(s1
);
280 isTric
= false; // s1 is a cut vertex
286 bool up
= (m_NUMBER
[e
->target()] - m_NUMBER
[e
->source()] > 0);
287 if ((up
&& m_TYPE
[e
] == frond
) || (!up
&& m_TYPE
[e
] == tree
))
293 buildAcceptableAdjStruct(GC
);
297 m_TSTACK_h
= new int[m
];
298 m_TSTACK_a
= new int[m
];
299 m_TSTACK_b
= new int[m
];
300 m_TSTACK_a
[m_top
= 0] = -1; // start with EOS
302 isTric
= pathSearch(G
,m_start
,s1
,s2
);
304 s1
= GC
.original(s1
);
305 s2
= GC
.original(s2
);
308 delete [] m_TSTACK_h
;
309 delete [] m_TSTACK_a
;
310 delete [] m_TSTACK_b
;
313 m_NUMBER
.init(); m_LOWPT1
.init();
314 m_LOWPT2
.init(); m_FATHER
.init();
315 m_ND
.init(); m_TYPE
.init();
316 m_A
.init(); m_NEWNUM
.init();
317 m_HIGHPT
.init(); m_START
.init();
318 m_DEGREE
.init(); m_TREE_ARC
.init();
319 m_IN_ADJ
.init(); m_IN_HIGH
.init();
324 //----------------------------------------------------------
327 // Splits bundles of multi-edges into bonds and creates
328 // a new virtual edge in GC.
329 //----------------------------------------------------------
331 void TricComp::splitMultiEdges()
333 GraphCopySimple
&GC
= *m_pGC
;
335 SListPure
<edge
> edges
;
336 EdgeArray
<int> minIndex(GC
), maxIndex(GC
);
337 parallelFreeSortUndirected(GC
,edges
,minIndex
,maxIndex
);
339 SListIterator
<edge
> it
;
340 for (it
= edges
.begin(); it
.valid(); ) {
342 int minI
= minIndex
[e
], maxI
= maxIndex
[e
];
344 if (it
.valid() && minI
== minIndex
[*it
] && maxI
== maxIndex
[*it
]) {
345 CompStruct
&C
= newComp(bond
);
346 C
<< GC
.newEdge(e
->source(),e
->target()) << e
<< *it
;
347 m_TYPE
[e
] = m_TYPE
[*it
] = removed
;
349 for (++it
; it
.valid() &&
350 minI
== minIndex
[*it
] && maxI
== maxIndex
[*it
]; ++it
)
353 m_TYPE
[*it
] = removed
;
361 //----------------------------------------------------------
364 // Checks if computed triconnected components are correct.
365 //----------------------------------------------------------
367 bool TricComp::checkSepPair(edge eVirt
)
369 GraphCopySimple
G(*m_pGC
);
371 G
.delNode(G
.copy(m_pGC
->original(eVirt
->source())));
372 G
.delNode(G
.copy(m_pGC
->original(eVirt
->target())));
374 return !isConnected(G
);
377 bool TricComp::checkComp()
381 GraphCopySimple
&GC
= *m_pGC
;
382 GraphCopySimple
GTest(GC
.original());
384 if (!isLoopFree(GC
)) {
386 cout
<< "GC contains loops!" << endl
;
393 EdgeArray
<int> count(GC
,0);
394 for (i
= 0; i
< m_numComp
; i
++) {
395 ListIterator
<edge
> itE
;
396 for(itE
= m_component
[i
].m_edges
.begin(); itE
.valid(); ++itE
)
401 if (GC
.original(e
) == 0) {
404 cout
<< "virtual edge contained " << count
[e
];
405 printOs(e
); cout
<< endl
;
407 if (checkSepPair(e
) == false) {
409 cout
<< "virtual edge"; printOs(e
);
410 cout
<< " does not correspond to a sep. pair." << endl
;
416 cout
<< "real edge contained " << count
[e
];
417 printOs(e
); cout
<< endl
;
423 NodeArray
<node
> map(GC
);
425 for(i
= 0; i
< m_numComp
; i
++) {
426 CompStruct
&C
= m_component
[i
];
427 const List
<edge
> &L
= C
.m_edges
;
428 if (L
.size() == 0) continue;
432 ListConstIterator
<edge
> itE
;
433 for(itE
= L
.begin(); itE
.valid(); ++itE
) {
434 S
.insert((*itE
)->source());
435 S
.insert((*itE
)->target());
438 const int n
= S
.size();
444 cout
<< "bond [" << i
<< "] with " << n
<< " nodes!" << endl
;
451 cout
<< "polygon [" << i
<< "] with " << n
<< " nodes!" << endl
;
456 cout
<< "polygon [" << i
<< "] with " << n
<< " vertices and " << L
.size() << " edges!" << endl
;
460 ListConstIterator
<node
> itV
;
461 for(itV
= S
.nodes().begin(); itV
.valid(); ++itV
)
462 map
[*itV
] = Gp
.newNode();
463 for(itE
= L
.begin(); itE
.valid(); ++itE
)
464 Gp
.newEdge(map
[(*itE
)->source()],map
[(*itE
)->target()]);
467 if (v
->degree() != 2) {
469 cout
<< "polygon [" << i
<< "] contains node with degree " << v
->degree() << endl
;
471 if (!isConnected(Gp
)) {
473 cout
<< "polygon [" << i
<< "] not connected." << endl
;
481 cout
<< "triconnected component [" << i
<< "] with " << n
<< " nodes!" << endl
;
486 ListConstIterator
<node
> itV
;
487 for(itV
= S
.nodes().begin(); itV
.valid(); ++itV
)
488 map
[*itV
] = Gp
.newNode();
489 for(itE
= L
.begin(); itE
.valid(); ++itE
)
490 Gp
.newEdge(map
[(*itE
)->source()],map
[(*itE
)->target()]);
492 if (!isTriconnectedPrimitive(Gp
)) {
494 cout
<< "component [" << i
<< "] not triconnected!" << endl
;
498 cout
<< "triconnected component [" << i
<< "] not simple!" << endl
;
505 cout
<< "component [" << i
<< "] with undefined type!" << endl
;
513 //----------------------------------------------------------
514 // assembleTriconnectedComponents
516 // joins bonds and polygons with common virtual edge in
517 // order to build the triconnected components.
518 //----------------------------------------------------------
520 void TricComp::assembleTriconnectedComponents()
522 GraphCopySimple
&GC
= *m_pGC
;
524 EdgeArray
<int> comp1(GC
), comp2(GC
);
525 EdgeArray
<ListIterator
<edge
> > item1(GC
,ListIterator
<edge
>());
526 EdgeArray
<ListIterator
<edge
> > item2(GC
);
528 bool *visited
= new bool[m_numComp
];
531 for(i
= 0; i
< m_numComp
; i
++) {
533 List
<edge
> &L
= m_component
[i
].m_edges
;
535 ListIterator
<edge
> it
;
536 for(it
= L
.begin(); it
.valid(); ++it
) {
538 if (!item1
[e
].valid()) {
539 comp1
[e
] = i
; item1
[e
] = it
;
541 comp2
[e
] = i
; item2
[e
] = it
;
546 for(i
= 0; i
< m_numComp
; i
++) {
547 CompStruct
&C1
= m_component
[i
];
548 List
<edge
> &L1
= C1
.m_edges
;
551 if (L1
.size() == 0) continue;
553 if (C1
.m_type
== polygon
|| C1
.m_type
== bond
) {
554 ListIterator
<edge
> it
, itNext
;
555 for(it
= L1
.begin(); it
.valid(); it
= itNext
) {
559 if (GC
.original(e
) != 0) continue;
562 ListIterator
<edge
> it2
;
565 if (visited
[j
]) continue;
570 CompStruct
&C2
= m_component
[j
];
572 if (C2
.m_type
!= C1
.m_type
) continue;
575 List
<edge
> &L2
= C2
.m_edges
;
593 //----------------------------------------------------------
594 // The first dfs-search
596 // computes NUMBER[v], FATHER[v], LOWPT1[v], LOWPT2[v],
597 // ND[v], TYPE[e], DEGREE[v]
598 //----------------------------------------------------------
600 void TricComp::DFS1 (const Graph
& G
, node v
, node u
)
604 m_NUMBER
[v
] = ++m_numCount
;
606 m_DEGREE
[v
] = v
->degree();
608 m_LOWPT1
[v
] = m_LOWPT2
[v
] = m_NUMBER
[v
];
611 forall_adj_edges (e
,v
) {
613 if (m_TYPE
[e
] != unseen
)
616 node w
= e
->opposite(v
);
618 if (m_NUMBER
[w
] == 0) {
625 if (m_LOWPT1
[w
] < m_LOWPT1
[v
]) {
626 m_LOWPT2
[v
] = min(m_LOWPT1
[v
],m_LOWPT2
[w
]);
627 m_LOWPT1
[v
] = m_LOWPT1
[w
];
629 } else if (m_LOWPT1
[w
] == m_LOWPT1
[v
]) {
630 m_LOWPT2
[v
] = min(m_LOWPT2
[v
],m_LOWPT2
[w
]);
633 m_LOWPT2
[v
] = min(m_LOWPT2
[v
],m_LOWPT1
[w
]);
642 if (m_NUMBER
[w
] < m_LOWPT1
[v
]) {
643 m_LOWPT2
[v
] = m_LOWPT1
[v
];
644 m_LOWPT1
[v
] = m_NUMBER
[w
];
646 } else if (m_NUMBER
[w
] > m_LOWPT1
[v
]) {
647 m_LOWPT2
[v
] = min(m_LOWPT2
[v
],m_NUMBER
[w
]);
653 void TricComp::DFS1 (const Graph
& G
, node v
, node u
, node
&s1
)
658 m_NUMBER
[v
] = ++m_numCount
;
660 m_DEGREE
[v
] = v
->degree();
662 m_LOWPT1
[v
] = m_LOWPT2
[v
] = m_NUMBER
[v
];
665 forall_adj_edges (e
,v
) {
667 if (m_TYPE
[e
] != unseen
)
670 node w
= e
->opposite(v
);
672 if (m_NUMBER
[w
] == 0) {
674 if(firstSon
== 0) firstSon
= w
;
680 // check for cut vertex
681 if(m_LOWPT1
[w
] >= m_NUMBER
[v
] && (w
!= firstSon
|| u
!= 0))
684 if (m_LOWPT1
[w
] < m_LOWPT1
[v
]) {
685 m_LOWPT2
[v
] = min(m_LOWPT1
[v
],m_LOWPT2
[w
]);
686 m_LOWPT1
[v
] = m_LOWPT1
[w
];
688 } else if (m_LOWPT1
[w
] == m_LOWPT1
[v
]) {
689 m_LOWPT2
[v
] = min(m_LOWPT2
[v
],m_LOWPT2
[w
]);
692 m_LOWPT2
[v
] = min(m_LOWPT2
[v
],m_LOWPT1
[w
]);
701 if (m_NUMBER
[w
] < m_LOWPT1
[v
]) {
702 m_LOWPT2
[v
] = m_LOWPT1
[v
];
703 m_LOWPT1
[v
] = m_NUMBER
[w
];
705 } else if (m_NUMBER
[w
] > m_LOWPT1
[v
]) {
706 m_LOWPT2
[v
] = min(m_LOWPT2
[v
],m_NUMBER
[w
]);
713 //----------------------------------------------------------
714 // Construction of ordered adjaceny lists
715 //----------------------------------------------------------
717 void TricComp::buildAcceptableAdjStruct(const Graph
& G
)
720 int max
= 3*G
.numberOfNodes()+2;
721 Array
<List
<edge
> > BUCKET(1,max
);
724 edgeType t
= m_TYPE
[e
];
725 if (t
== removed
) continue;
727 node w
= e
->target();
728 int phi
= (t
== frond
) ? 3*m_NUMBER
[w
]+1 : (
729 (m_LOWPT2
[w
] < m_NUMBER
[e
->source()]) ? 3*m_LOWPT1
[w
] :
731 BUCKET
[phi
].pushBack(e
);
734 for (int i
= 1; i
<= max
; i
++) {
735 ListConstIterator
<edge
> it
;
736 for(it
= BUCKET
[i
].begin(); it
.valid(); ++it
) {
738 m_IN_ADJ
[e
] = m_A
[e
->source()].pushBack(e
);
744 //----------------------------------------------------------
745 // The second dfs-search
746 //----------------------------------------------------------
748 void TricComp::pathFinder(const Graph
& G
, node v
)
750 m_NEWNUM
[v
] = m_numCount
- m_ND
[v
] + 1;
752 ListConstIterator
<edge
> it
;
753 for(it
= m_A
[v
].begin(); it
.valid(); ++it
) {
755 node w
= e
->opposite(v
);
762 if (m_TYPE
[e
] == tree
) {
767 m_IN_HIGH
[e
] = m_HIGHPT
[w
].pushBack(m_NEWNUM
[v
]);
773 void TricComp::DFS2 (const Graph
& G
)
777 m_IN_HIGH
.init(G
,ListIterator
<int>());
778 m_START
.init(G
,false);
780 m_numCount
= G
.numberOfNodes();
783 pathFinder(G
,m_start
);
786 Array
<int> old2new(1,G
.numberOfNodes());
789 old2new
[m_NUMBER
[v
]] = m_NEWNUM
[v
];
792 m_NODEAT
[m_NEWNUM
[v
]] = v
;
793 m_LOWPT1
[v
] = old2new
[m_LOWPT1
[v
]];
794 m_LOWPT2
[v
] = old2new
[m_LOWPT2
[v
]];
799 //----------------------------------------------------------
802 // recognition of split components
803 //----------------------------------------------------------
805 void TricComp::pathSearch (const Graph
& G
, node v
)
809 int y
, vnum
= m_NEWNUM
[v
], wnum
;
812 List
<edge
> &Adj
= m_A
[v
];
813 int outv
= Adj
.size();
815 ListIterator
<edge
> it
, itNext
;
816 for(it
= Adj
.begin(); it
.valid(); it
=itNext
)
820 w
= e
->target(); wnum
= m_NEWNUM
[w
];
822 if (m_TYPE
[e
] == tree
) {
826 if (m_TSTACK_a
[m_top
] > m_LOWPT1
[w
]) {
828 y
= max(y
,m_TSTACK_h
[m_top
]);
829 b
= m_TSTACK_b
[m_top
--];
830 } while (m_TSTACK_a
[m_top
] > m_LOWPT1
[w
]);
831 TSTACK_push(y
,m_LOWPT1
[w
],b
);
833 TSTACK_push(wnum
+m_ND
[w
]-1,m_LOWPT1
[w
],vnum
);
840 m_ESTACK
.push(m_TREE_ARC
[w
]); // add (v,w) to ESTACK (can differ from e!)
844 while (vnum
!= 1 && ((m_TSTACK_a
[m_top
] == vnum
) ||
845 (m_DEGREE
[w
] == 2 && m_NEWNUM
[m_A
[w
].front()->target()] > wnum
)))
847 a
= m_TSTACK_a
[m_top
];
848 b
= m_TSTACK_b
[m_top
];
852 if (a
== vnum
&& m_FATHER
[m_NODEAT
[b
]] == m_NODEAT
[a
]) {
859 if (m_DEGREE
[w
] == 2 && m_NEWNUM
[m_A
[w
].front()->target()] > wnum
) {
860 #ifdef TRIC_COMP_OUTPUT
861 cout
<< endl
<< "\nfound type-2 separation pair " <<
862 m_pGC
->original(v
) << ", " <<
863 m_pGC
->original(m_A
[w
].front()->target());
866 edge e1
= m_ESTACK
.pop();
867 edge e2
= m_ESTACK
.pop();
868 m_A
[w
].del(m_IN_ADJ
[e2
]);
872 eVirt
= m_pGC
->newEdge(v
,x
);
873 m_DEGREE
[x
]--; m_DEGREE
[v
]--;
875 OGDF_ASSERT(e2
->source() == w
);
876 CompStruct
&C
= newComp(polygon
);
877 C
<< e1
<< e2
<< eVirt
;
879 if (!m_ESTACK
.empty()) {
881 if (e1
->source() == x
&& e1
->target() == v
) {
882 e_ab
= m_ESTACK
.pop();
883 m_A
[x
].del(m_IN_ADJ
[e_ab
]);
889 #ifdef TRIC_COMP_OUTPUT
890 cout
<< "\nfound type-2 separation pair " <<
891 m_pGC
->original(m_NODEAT
[a
]) << ", " <<
892 m_pGC
->original(m_NODEAT
[b
]);
895 int h
= m_TSTACK_h
[m_top
--];
897 CompStruct
&C
= newComp();
899 edge xy
= m_ESTACK
.top();
900 x
= xy
->source(); node y
= xy
->target();
901 if (!(a
<= m_NEWNUM
[x
] && m_NEWNUM
[x
] <= h
&&
902 a
<= m_NEWNUM
[y
] && m_NEWNUM
[y
] <= h
)) break;
904 if ((m_NEWNUM
[x
] == a
&& m_NEWNUM
[y
] == b
) ||
905 (m_NEWNUM
[y
] == a
&& m_NEWNUM
[x
] == b
))
907 e_ab
= m_ESTACK
.pop();
908 m_A
[e_ab
->source()].del(m_IN_ADJ
[e_ab
]);
912 edge eh
= m_ESTACK
.pop();
913 if (it
!= m_IN_ADJ
[eh
]) {
914 m_A
[eh
->source()].del(m_IN_ADJ
[eh
]);
918 m_DEGREE
[x
]--; m_DEGREE
[y
]--;
922 eVirt
= m_pGC
->newEdge(m_NODEAT
[a
],m_NODEAT
[b
]);
923 C
.finishTricOrPoly(eVirt
);
928 CompStruct
&C
= newComp(bond
);
931 eVirt
= m_pGC
->newEdge(v
,x
);
934 m_DEGREE
[x
]--; m_DEGREE
[v
]--;
937 m_ESTACK
.push(eVirt
);
939 m_IN_ADJ
[eVirt
] = it
;
941 m_DEGREE
[x
]++; m_DEGREE
[v
]++;
943 m_TREE_ARC
[x
] = eVirt
;
944 m_TYPE
[eVirt
] = tree
;
946 w
= x
; wnum
= m_NEWNUM
[w
];
950 if (m_LOWPT2
[w
] >= vnum
&& m_LOWPT1
[w
] < vnum
&& (m_FATHER
[v
] != m_start
|| outv
>= 2))
952 #ifdef TRIC_COMP_OUTPUT
953 cout
<< "\nfound type-1 separation pair " <<
954 m_pGC
->original(m_NODEAT
[m_LOWPT1
[w
]]) << ", " <<
958 CompStruct
&C
= newComp();
961 while (!m_ESTACK
.empty()) {
963 x
= m_NEWNUM
[xy
->source()];
964 y
= m_NEWNUM
[xy
->target()];
966 if (!((wnum
<= x
&& x
< wnum
+m_ND
[w
]) || (wnum
<= y
&& y
< wnum
+m_ND
[w
])))
971 m_DEGREE
[m_NODEAT
[x
]]--; m_DEGREE
[m_NODEAT
[y
]]--;
974 edge eVirt
= m_pGC
->newEdge(v
,m_NODEAT
[m_LOWPT1
[w
]]);
975 C
.finishTricOrPoly(eVirt
);
977 if ((x
== vnum
&& y
== m_LOWPT1
[w
]) || (y
== vnum
&& x
== m_LOWPT1
[w
])) {
978 CompStruct
&C
= newComp(bond
);
979 edge eh
= m_ESTACK
.pop();
980 if (m_IN_ADJ
[eh
] != it
) {
981 m_A
[eh
->source()].del(m_IN_ADJ
[eh
]);
984 eVirt
= m_pGC
->newEdge(v
,m_NODEAT
[m_LOWPT1
[w
]]);
986 m_IN_HIGH
[eVirt
] = m_IN_HIGH
[eh
];
988 m_DEGREE
[m_NODEAT
[m_LOWPT1
[w
]]]--;
991 if (m_NODEAT
[m_LOWPT1
[w
]] != m_FATHER
[v
]) {
992 m_ESTACK
.push(eVirt
);
994 m_IN_ADJ
[eVirt
] = it
;
995 if (!m_IN_HIGH
[eVirt
].valid() && high(m_NODEAT
[m_LOWPT1
[w
]]) < vnum
)
996 m_IN_HIGH
[eVirt
] = m_HIGHPT
[m_NODEAT
[m_LOWPT1
[w
]]].pushFront(vnum
);
999 m_DEGREE
[m_NODEAT
[m_LOWPT1
[w
]]]++;
1004 CompStruct
&C
= newComp(bond
);
1006 eVirt
= m_pGC
->newEdge(m_NODEAT
[m_LOWPT1
[w
]],v
);
1009 edge eh
= m_TREE_ARC
[v
];
1013 m_TREE_ARC
[v
] = eVirt
;
1014 m_TYPE
[eVirt
] = tree
;
1016 m_IN_ADJ
[eVirt
] = m_IN_ADJ
[eh
];
1017 *m_IN_ADJ
[eh
] = eVirt
;
1022 while (TSTACK_notEOS()) {
1028 while (TSTACK_notEOS() &&
1029 m_TSTACK_b
[m_top
] != vnum
&& high(v
) > m_TSTACK_h
[m_top
]) {
1035 } else { // frond arc
1038 if (m_TSTACK_a
[m_top
] > wnum
) {
1040 y
= max(y
,m_TSTACK_h
[m_top
]);
1041 b
= m_TSTACK_b
[m_top
--];
1042 } while (m_TSTACK_a
[m_top
] > wnum
);
1043 TSTACK_push(y
,wnum
,b
);
1045 TSTACK_push(vnum
,wnum
,vnum
);
1049 m_ESTACK
.push(e
); // add (v,w) to ESTACK
1054 // simplified path search for triconnectivity test
1055 bool TricComp::pathSearch (const Graph
&G
, node v
, node
&s1
, node
&s2
)
1059 int y
, vnum
= m_NEWNUM
[v
], wnum
;
1062 List
<edge
> &Adj
= m_A
[v
];
1063 int outv
= Adj
.size();
1065 ListIterator
<edge
> it
, itNext
;
1066 for(it
= Adj
.begin(); it
.valid(); it
=itNext
)
1070 w
= e
->target(); wnum
= m_NEWNUM
[w
];
1072 if (m_TYPE
[e
] == tree
) {
1076 if (m_TSTACK_a
[m_top
] > m_LOWPT1
[w
]) {
1078 y
= max(y
,m_TSTACK_h
[m_top
]);
1079 b
= m_TSTACK_b
[m_top
--];
1080 } while (m_TSTACK_a
[m_top
] > m_LOWPT1
[w
]);
1081 TSTACK_push(y
,m_LOWPT1
[w
],b
);
1083 TSTACK_push(wnum
+m_ND
[w
]-1,m_LOWPT1
[w
],vnum
);
1088 if(pathSearch(G
,w
,s1
,s2
) == false)
1091 while (vnum
!= 1 && ((m_TSTACK_a
[m_top
] == vnum
) ||
1092 (m_DEGREE
[w
] == 2 && m_NEWNUM
[m_A
[w
].front()->target()] > wnum
)))
1094 a
= m_TSTACK_a
[m_top
];
1095 b
= m_TSTACK_b
[m_top
];
1097 if (a
== vnum
&& m_FATHER
[m_NODEAT
[b
]] == m_NODEAT
[a
]) {
1100 } else if (m_DEGREE
[w
] == 2 && m_NEWNUM
[m_A
[w
].front()->target()] > wnum
)
1103 s2
= m_A
[w
].front()->target();
1113 if (m_LOWPT2
[w
] >= vnum
&& m_LOWPT1
[w
] < vnum
&& (m_FATHER
[v
] != m_start
|| outv
>= 2))
1115 s1
= m_NODEAT
[m_LOWPT1
[w
]];
1121 while (TSTACK_notEOS()) {
1127 while (TSTACK_notEOS() &&
1128 m_TSTACK_b
[m_top
] != vnum
&& high(v
) > m_TSTACK_h
[m_top
]) {
1134 } else { // frond arc
1137 if (m_TSTACK_a
[m_top
] > wnum
) {
1139 y
= max(y
,m_TSTACK_h
[m_top
]);
1140 b
= m_TSTACK_b
[m_top
--];
1141 } while (m_TSTACK_a
[m_top
] > wnum
);
1142 TSTACK_push(y
,wnum
,b
);
1144 TSTACK_push(vnum
,wnum
,vnum
);
1154 // triconnectivity test
1155 bool isTriconnected(const Graph
&G
, node
&s1
, node
&s2
)
1158 TricComp
tric2(G
,isTric
,s1
,s2
);
1164 //----------------------------------------------------------
1166 //----------------------------------------------------------
1168 void TricComp::printOs(edge e
)
1170 #ifdef TRIC_COMP_OUTPUT
1171 cout
<< " (" << m_pGC
->original(e
->source()) << "," <<
1172 m_pGC
->original(e
->target()) << "," << e
->index() << ")";
1173 if (m_pGC
->original(e
) == 0) cout
<< "v";
1177 void TricComp::printStacks()
1179 #ifdef TRIC_COMP_OUTPUT
1180 cout
<< "\n\nTSTACK:" << endl
;
1182 for (int i
= m_top
; i
>= 0; i
--)
1183 cout
<< "(" << m_TSTACK_h
[i
] << "," << m_TSTACK_a
[i
] << "," << m_TSTACK_b
[i
] << ")\n";
1185 cout
<< "\nESTACK\n";
1186 while(!m_ESTACK
.empty()) {
1187 printOs(m_ESTACK
.pop()); cout
<< endl
;
1193 } // end namespace ogdf