1 /** \file
2 * \brief Declaration of simple graph algorithms.
3 *
4 * \author Carsten Gutwenger and Sebastian Leipert
5 *
6 * \par License:
7 * This file is part of the Open Graph Drawing Framework (OGDF).
8 *
9 * \par
10 * Copyright (C)<br>
11 * See README.md in the OGDF root directory for details.
12 *
13 * \par
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * Version 2 or 3 as published by the Free Software Foundation;
17 * see the file LICENSE.txt included in the packaging of this file
18 * for details.
19 *
20 * \par
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * \par
27 * You should have received a copy of the GNU General Public
28 * License along with this program; if not, see
29 * http://www.gnu.org/copyleft/gpl.html
30 */
31
32 #pragma once
33
34 #include <ogdf/basic/NodeArray.h>
35 #include <ogdf/basic/EdgeArray.h>
36 #include <ogdf/basic/SList.h>
37
38 namespace ogdf {
39
40 //! \name Methods for loops
41 //! @{
42
43 /**
44 * Removes all self-loops for a given node \p v in \p graph
45 *
46 * @ingroup ga-multi
47 */
48 OGDF_EXPORT void removeSelfLoops(Graph &graph, node v);
49
50 //! Returns true iff \p G contains no self-loop.
51 /**
52 * @ingroup ga-multi
53 *
54 * @param G is the input graph.
55 * @return true if \p G contains no self-loops (edges whose two endpoints are the same), false otherwise.
56 */
57 OGDF_EXPORT bool isLoopFree(const Graph &G);
58
59 //! Removes all self-loops from \p G and returns all nodes with self-loops in \p L.
60 /**
61 * @ingroup ga-multi
62 *
63 * @tparam NODELIST is the type of the node list for returning the nodes with self-loops.
64 * @param G is the input graph.
65 * @param L is assigned the list of nodes with self-loops.
66 */
67 template<class NODELIST>
makeLoopFree(Graph & G,NODELIST & L)68 void makeLoopFree(Graph &G, NODELIST &L)
69 {
70 L.clear();
71
72 safeForEach(G.edges, [&](edge e) {
73 if (e->isSelfLoop()) {
74 L.pushBack(e->source());
75 G.delEdge(e);
76 }
77 });
78 }
79
80 //! Returns whether \p G has edges which are not self-loops.
81 OGDF_EXPORT bool hasNonSelfLoopEdges(const Graph &G);
82
83 //! Removes all self-loops from \p G.
84 /**
85 * @ingroup ga-multi
86 *
87 * @param G is the input graph.
88 */
89 OGDF_EXPORT void makeLoopFree(Graph &G);
90
91
92 //! @}
93 //! \name Methods for parallel edges
94 //! @{
95
96 //! Sorts the edges of \p G such that parallel edges come after each other in the list.
97 /**
98 * @ingroup ga-multi
99 *
100 * @param G is the input graph.
101 * @param edges is assigned the list of sorted edges.
102 */
103 OGDF_EXPORT void parallelFreeSort(const Graph &G, SListPure<edge> &edges);
104
105
106 //! Returns true iff \p G contains no parallel edges.
107 /**
108 * @ingroup ga-multi
109 *
110 * A parallel edge is an edge e1=(v,w) such that there exists another edge e2=(v,w) in
111 * the graph. Reversal edges (e.g. (v,w) and (w,v)) are not parallel edges. If you want to
112 * test if a graph contains no undirected parallel edges, use isParallelFreeUndirected().
113 *
114 * @param G is the input graph.
115 * @return true if \p G contains no multi-edges (edges with the same source and target).
116 */
117 OGDF_EXPORT bool isParallelFree(const Graph &G);
118
119
120 //! Returns the number of parallel edges in \p G.
121 /**
122 * @ingroup ga-multi
123 *
124 * A parallel edge is an edge e1=(v,w) such that there exists another edge e2=(v,w) in
125 * the graph. Reversal edges (e.g. (v,w) and (w,v)) are not parallel edges. If you want to
126 * also take reversal edges into account, use numParallelEdgesUndirected().
127 *
128 * @param G is the input graph.
129 * @tparam ONLY_ONCE Whether the searching for multi-edges should be stopped
130 * once a single multi-edge is found.
131 * @return is the number of parallel edges: for each bundle of parallel edges between two nodes
132 * v and w, all but one are counted.
133 */
134 template <bool ONLY_ONCE = false>
numParallelEdges(const Graph & G)135 int numParallelEdges(const Graph &G) {
136 if (G.numberOfEdges() <= 1) return 0;
137
138 SListPure<edge> edges;
139 parallelFreeSort(G,edges);
140
141 int num = 0;
142 SListConstIterator<edge> it = edges.begin();
143 edge ePrev = *it, e;
144 for(it = ++it; it.valid(); ++it, ePrev = e) {
145 e = *it;
146 if (ePrev->isParallelDirected(e)) {
147 ++num;
148 if (ONLY_ONCE) {
149 return num;
150 }
151 }
152 }
153
154 return num;
155 }
156
157 //! Removes all but one of each bundle of parallel edges.
158 /**
159 * @ingroup ga-multi
160 *
161 * A parallel edge is an edge e1=(v,w) such that there exists another edge e2=(v,w) in
162 * the graph. Reversal edges (e.g. (v,w) and (w,v)) are not multi-edges. If you want to
163 * remove parallel and reversal edges, use ogdf::makeParallelFreeUndirected().
164 *
165 * @tparam EDGELIST is the type of edge list that will be assigned the list of parallel edges.
166 * @param G is the input graph.
167 * @param parallelEdges is assigned the list of remaining edges in \p G that were part of a
168 * bundle of parallel edges in the input graph.
169 */
170 template <class EDGELIST>
makeParallelFree(Graph & G,EDGELIST & parallelEdges)171 void makeParallelFree(Graph &G, EDGELIST ¶llelEdges)
172 {
173 parallelEdges.clear();
174 if (G.numberOfEdges() <= 1) return;
175
176 SListPure<edge> edges;
177 parallelFreeSort(G,edges);
178
179 SListConstIterator<edge> it = edges.begin();
180 edge ePrev = *it++, e;
181 bool bAppend = true;
182 while(it.valid()) {
183 e = *it++;
184 if (e->isParallelDirected(ePrev)) {
185 G.delEdge(e);
186 if (bAppend) { parallelEdges.pushBack(ePrev); bAppend = false; }
187 } else {
188 ePrev = e; bAppend = true;
189 }
190 }
191 }
192
193
194 //! Removes all but one edge of each bundle of parallel edges in \p G.
195 /**
196 * @ingroup ga-multi
197 *
198 * A parallel edge is an edge e1=(v,w) such that there exists another edge e2=(v,w) in
199 * the graph. Reversal edges (e.g. (v,w) and (w,v)) are not parallel edges. If you want to
200 * remove parallel and reversal edges, use ogdf::makeParallelFreeUndirected().
201 *
202 * @param G is the input graph.
203 */
makeParallelFree(Graph & G)204 inline void makeParallelFree(Graph &G) {
205 List<edge> parallelEdges;
206 makeParallelFree(G,parallelEdges);
207 }
208
209
210
211 //! Sorts the edges of \p G such that undirected parallel edges come after each other in the list.
212 /**
213 * @ingroup ga-multi
214 *
215 * An undirected parallel edges is an edge e1=(v,w) such that there exists another edge e2=(v,w) or (w,v)
216 * in the graph.
217 *
218 * @param G is the input graph.
219 * @param edges is assigned the list of sorted edges.
220 * @param minIndex is assigned for each edge (v,w) the index min(index(v),index(w)).
221 * @param maxIndex is assigned for each edge (v,w) the index max(index(v),index(w)).
222 */
223 OGDF_EXPORT void parallelFreeSortUndirected(
224 const Graph &G,
225 SListPure<edge> &edges,
226 EdgeArray<int> &minIndex,
227 EdgeArray<int> &maxIndex);
228
229
230 //! Returns true iff \p G contains no undirected parallel edges.
231 /**
232 * @ingroup ga-multi
233 *
234 * An undirected parallel edges is an edge e1=(v,w) such that there exists another edge e2=(v,w) or (w,v)
235 * in the graph.
236 *
237 * @param G is the input graph.
238 * @return true if \p G contains no undirected parallel edges.
239 */
240 OGDF_EXPORT bool isParallelFreeUndirected(const Graph &G);
241
242
243 //! Returns the number of undirected parallel edges in \p G.
244 /**
245 * @ingroup ga-multi
246 *
247 * An undirected parallel edges is an edge e1=(v,w) such that there exists another edge e2=(v,w) or (w,v)
248 * in the graph.
249 *
250 * @param G is the input graph.
251 * @tparam ONLY_ONCE Whether the searching for multi-edges should be stopped
252 * once a single multi-edge is found.
253 * @return the number of undirected parallel edges; for each unordered pair {v,w} of nodes, all
254 * but one of the edges with endpoints v and w (in any order) are counted.
255 */
256 template <bool ONLY_ONCE = false>
numParallelEdgesUndirected(const Graph & G)257 int numParallelEdgesUndirected(const Graph &G)
258 {
259 if (G.numberOfEdges() <= 1) return 0;
260
261 SListPure<edge> edges;
262 EdgeArray<int> minIndex(G), maxIndex(G);
263 parallelFreeSortUndirected(G,edges,minIndex,maxIndex);
264
265 int num = 0;
266 SListConstIterator<edge> it = edges.begin();
267 edge ePrev = *it, e;
268 for(it = ++it; it.valid(); ++it, ePrev = e) {
269 e = *it;
270 if (minIndex[ePrev] == minIndex[e] && maxIndex[ePrev] == maxIndex[e]) {
271 ++num;
272 if (ONLY_ONCE) {
273 return num;
274 }
275 }
276 }
277
278 return num;
279 }
280
281
282 //! Computes the bundles of undirected parallel edges in \p G.
283 /**
284 * @ingroup ga-multi
285 *
286 * Stores for one (arbitrarily chosen) reference edge all edges belonging to the same bundle of
287 * undirected parallel edges; no edge is removed from the graph.
288 *
289 * @tparam EDGELIST is the type of edge list that is assigned the list of edges.
290 * @param G is the input graph.
291 * @param parallelEdges is assigned for each reference edge the list of edges belonging to the
292 * bundle of undirected parallel edges.
293 */
294 template <class EDGELIST>
getParallelFreeUndirected(const Graph & G,EdgeArray<EDGELIST> & parallelEdges)295 void getParallelFreeUndirected(const Graph &G, EdgeArray<EDGELIST> ¶llelEdges)
296 {
297 if (G.numberOfEdges() <= 1) {
298 return;
299 }
300
301 SListPure<edge> edges;
302 EdgeArray<int> minIndex(G), maxIndex(G);
303 parallelFreeSortUndirected(G,edges,minIndex,maxIndex);
304
305 SListConstIterator<edge> it = edges.begin();
306 edge ePrev = *it++, e;
307 while (it.valid()) {
308 e = *it++;
309 if (minIndex[ePrev] == minIndex[e] && maxIndex[ePrev] == maxIndex[e]) {
310 parallelEdges[ePrev].pushBack(e);
311 } else {
312 ePrev = e;
313 }
314 }
315 }
316
317
318 //! Removes all but one edge of each bundle of undirected parallel edges.
319 /**
320 * @ingroup ga-multi
321 *
322 * An undirected parallel edge is an edge e1=(v,w) such that there exists
323 * another edge e2=(v,w) or (w,v) in the graph. This function removes all but
324 * one of the edges with endpoints v and w for each unordered pair of nodes
325 * {v,w}.
326 *
327 * @tparam EDGELIST is the type of edge list that will be assigned the list of edges.
328 * @param G is the input graph.
329 * @param parallelEdges is assigned the list of remaining edges that were part of a bundle
330 * of undirected parallel edges in the input graph.
331 * @param cardPositive contains for each edge the number of removed undirected parallel edges
332 * pointing in the same direction.
333 * @param cardNegative contains for each edge the number of removed undirected parallel edges
334 * pointing in the opposite direction.
335 */
336 template <class EDGELIST = SListPure<edge>>
337 void makeParallelFreeUndirected(
338 Graph &G,
339 EDGELIST *parallelEdges = nullptr,
340 EdgeArray<int> *cardPositive = nullptr,
341 EdgeArray<int> *cardNegative = nullptr)
342 {
343 if (parallelEdges != nullptr) { parallelEdges->clear(); }
344 if (cardPositive != nullptr) { cardPositive->fill(0); }
345 if (cardNegative != nullptr) { cardNegative->fill(0); }
346
347 if (G.numberOfEdges() <= 1) {
348 return;
349 }
350
351 EdgeArray<SListPure<edge>> parEdges(G);
352 getParallelFreeUndirected(G, parEdges);
353
354 for (edge e : G.edges) {
355 for (edge parEdge : parEdges(e)) {
356 if (cardPositive != nullptr && e->source() == parEdge->source()) {
357 (*cardPositive)[e]++;
358 }
359 if (cardNegative != nullptr && e->source() == parEdge->target()) {
360 (*cardNegative)[e]++;
361 }
362 G.delEdge(parEdge);
363 if (parallelEdges != nullptr) {
364 parallelEdges->pushBack(e);
365 }
366 }
367 }
368 }
369
370
371 /**
372 * @ingroup ga-multi
373 */
374 template <class EDGELIST>
375 OGDF_DEPRECATED("The pointer-based makeParallelFreeUndirected() should be used instead.")
makeParallelFreeUndirected(Graph & G,EDGELIST & parallelEdges)376 void makeParallelFreeUndirected(Graph &G, EDGELIST ¶llelEdges) {
377 makeParallelFreeUndirected(G, ¶llelEdges);
378 }
379
380 /**
381 * @ingroup ga-multi
382 */
383 template <class EDGELIST>
384 OGDF_DEPRECATED("The pointer-based makeParallelFreeUndirected() should be used instead.")
makeParallelFreeUndirected(Graph & G,EDGELIST & parallelEdges,EdgeArray<int> & cardPositive,EdgeArray<int> & cardNegative)385 void makeParallelFreeUndirected(Graph &G,
386 EDGELIST ¶llelEdges,
387 EdgeArray<int> &cardPositive,
388 EdgeArray<int> &cardNegative) {
389 makeParallelFreeUndirected(G, ¶llelEdges, &cardPositive, &cardNegative);
390 }
391
392 //! @}
393 //! \name Methods for simple graphs
394 //! @{
395
396 //! Returns true iff \p G contains neither self-loops nor parallel edges.
397 /**
398 * @ingroup ga-multi
399 *
400 * @param G is the input graph.
401 * @return true if \p G is simple, i.e. contains neither self-loops nor parallel edges, false otherwise.
402 */
isSimple(const Graph & G)403 inline bool isSimple(const Graph &G) {
404 return isLoopFree(G) && isParallelFree(G);
405 }
406
407
408 //! Removes all self-loops and all but one edge of each bundle of parallel edges.
409 /**
410 * @ingroup ga-multi
411 *
412 * @param G is the input graph.
413 */
makeSimple(Graph & G)414 inline void makeSimple(Graph &G) {
415 makeLoopFree(G);
416 makeParallelFree(G);
417 }
418
419
420 //! Returns true iff \p G contains neither self-loops nor undirected parallel edges.
421 /**
422 * @ingroup ga-multi
423 *
424 * @param G is the input graph.
425 * @return true if \p G is (undirected) simple, i.e. contains neither self-loops
426 * nor undirected parallel edges, false otherwise.
427 */
isSimpleUndirected(const Graph & G)428 inline bool isSimpleUndirected(const Graph &G) {
429 return isLoopFree(G) && isParallelFreeUndirected(G);
430 }
431
432
433 //! Removes all self-loops and all but one edge of each bundle of undirected parallel edges.
434 /**
435 * @ingroup ga-multi
436 *
437 * @param G is the input graph.
438 */
makeSimpleUndirected(Graph & G)439 inline void makeSimpleUndirected(Graph &G) {
440 makeLoopFree(G);
441 makeParallelFreeUndirected(G);
442 }
443
444 //! @}
445 //! \name Methods for connectivity
446 //! @{
447
448 //! Returns true iff \p G is connected.
449 /**
450 * @ingroup ga-connectivity
451 *
452 * @param G is the input graph.
453 * @return true if \p G is connected, false otherwise.
454 */
455 OGDF_EXPORT bool isConnected(const Graph &G);
456
457
458 //! Makes \p G connected by adding a minimum number of edges.
459 /**
460 * @ingroup ga-connectivity
461 *
462 * @param G is the input graph.
463 * @param added is assigned the added edges.
464 */
465 OGDF_EXPORT void makeConnected(Graph &G, List<edge> &added);
466
467
468 //! makes \p G connected by adding a minimum number of edges.
469 /**
470 * @ingroup ga-connectivity
471 *
472 * @param G is the input graph.
473 */
makeConnected(Graph & G)474 inline void makeConnected(Graph &G) {
475 List<edge> added;
476 makeConnected(G,added);
477 }
478
479
480 //! Computes the connected components of \p G and optionally generates a list of
481 //! isolated nodes.
482 /**
483 * @ingroup ga-connectivity
484 *
485 * Assigns component numbers (0, 1, ...) to the nodes of \p G. The component
486 * number of each node is stored in the node array \p component.
487 *
488 * @param G is the input graph.
489 * @param component is assigned a mapping from nodes to component numbers.
490 * @param isolated is assigned the list of isolated nodes. An isolated node is
491 * a node without incident edges.
492 * @return the number of connected components.
493 */
494 OGDF_EXPORT int connectedComponents(const Graph &G,
495 NodeArray<int> &component,
496 List<node> *isolated = nullptr);
497
498
499 OGDF_DEPRECATED("connectedComponents() should be used instead.")
500 /**
501 * @ingroup ga-connectivity
502 * @copydoc ogdf::connectedComponents(const Graph&, NodeArray<int>&, List<node>*);
503 */
connectedIsolatedComponents(const Graph & G,List<node> & isolated,NodeArray<int> & component)504 inline int connectedIsolatedComponents(const Graph &G,
505 List<node> &isolated,
506 NodeArray<int> &component) {
507 return connectedComponents(G, component, &isolated);
508 }
509
510
511 //! Returns true iff \p G is biconnected.
512 /**
513 * @ingroup ga-connectivity
514 *
515 * @param G is the input graph.
516 * @param cutVertex If false is returned and \p G is connected, \p cutVertex is
517 * assigned a cut vertex in \p G, else it is assigned nullptr.
518 */
519 OGDF_EXPORT bool isBiconnected(const Graph &G, node &cutVertex);
520
521
522 //! Returns true iff \p G is biconnected.
523 /**
524 * @ingroup ga-connectivity
525 *
526 * @param G is the input graph.
527 */
isBiconnected(const Graph & G)528 inline bool isBiconnected(const Graph &G) {
529 node cutVertex;
530 return isBiconnected(G,cutVertex);
531 }
532
533
534 //! Makes \p G biconnected by adding edges.
535 /**
536 * @ingroup ga-connectivity
537 *
538 * @param G is the input graph.
539 * @param added is assigned the list of inserted edges.
540 */
541 OGDF_EXPORT void makeBiconnected(Graph &G, List<edge> &added);
542
543
544 //! Makes \p G biconnected by adding edges.
545 /**
546 * @ingroup ga-connectivity
547 *
548 * @param G is the input graph.
549 */
makeBiconnected(Graph & G)550 inline void makeBiconnected(Graph &G) {
551 List<edge> added;
552 makeBiconnected(G,added);
553 }
554
555
556 /**
557 * @ingroup ga-connectivity
558 * @copydoc ogdf::biconnectedComponents(const Graph&, EdgeArray<int>&)
559 * @param nonEmptyComponents is the number of non-empty components.
560 * The indices of \p component range from 0 to \p nonEmptyComponents - 1.
561 */
562 OGDF_EXPORT int biconnectedComponents(const Graph &G, EdgeArray<int> &component, int &nonEmptyComponents);
563
564 //! Computes the biconnected components of \p G.
565 /**
566 * @ingroup ga-connectivity
567 *
568 * Assigns component numbers (0, 1, ...) to the edges of \p G. The component
569 * number of each edge is stored in the edge array \p component. Each self-loop
570 * is counted as one biconnected component and has its own component number.
571 *
572 * @param G is the input graph.
573 * @param component is assigned a mapping from edges to component numbers.
574 * @return the number of biconnected components (including self-loops) + the
575 * number of nodes without neighbours (that is, the number of nodes who have no
576 * incident edges or whose incident edges are all self-loops).
577 */
biconnectedComponents(const Graph & G,EdgeArray<int> & component)578 inline int biconnectedComponents(const Graph &G, EdgeArray<int> &component) {
579 int doNotNeedTheValue;
580 return biconnectedComponents(G, component, doNotNeedTheValue);
581 }
582
583
584 /**
585 * @copydoc ogdf::isTwoEdgeConnected(const Graph&)
586 * @param bridge If false is returned and \p graph is connected, \p bridge is assigned a bridge in \p graph,
587 * else it is assigned \c nullptr
588 */
589 OGDF_EXPORT bool isTwoEdgeConnected(const Graph &graph, edge &bridge);
590
591 /**
592 * Returns true iff \p graph is 2-edge-connected.
593 * @ingroup ga-connectivity
594 *
595 * Implementation of the algorithm to determine 2-edge-connectivity from the following publication:
596 *
597 * Jens M. Schmidt: <i>A Simple Test on 2-Vertex- and 2-Edge-Connectivity</i>.
598 * Information Processing Letters (2013)
599 *
600 * It runs in O(|E|+|V|) as it relies on two DFS.
601 *
602 * @param graph is the input graph.
603 */
isTwoEdgeConnected(const Graph & graph)604 inline bool isTwoEdgeConnected(const Graph &graph) {
605 edge bridge;
606 return isTwoEdgeConnected(graph, bridge);
607 }
608
609
610 //! Returns true iff \p G is triconnected.
611 /**
612 * @ingroup ga-connectivity
613 *
614 * If \p G is not triconnected then
615 * - \p s1 and \p s2 are both \c nullptr if \p G is not connected.
616 * - \p s1 is a cut vertex and \p s2 is \c nullptr if \p G is connected but not biconnected.
617 * - \p s1 and \p s2 are a separation pair if \p G is bi- but not triconnected.
618 *
619 * @param G is the input graph.
620 * @param s1 is assigned a cut vertex or one node of a separation pair, if \p G is not triconnected (see above).
621 * @param s2 is assigned one node of a separation pair, if \p G is not triconnected (see above).
622 * @return true if \p G is triconnected, false otherwise.
623 */
624 OGDF_EXPORT bool isTriconnected(const Graph &G, node &s1, node &s2);
625
626
627 //! Returns true iff \p G is triconnected.
628 /**
629 * @ingroup ga-connectivity
630 *
631 * @param G is the input graph.
632 * @return true if \p G is triconnected, false otherwise.
633 */
isTriconnected(const Graph & G)634 inline bool isTriconnected(const Graph &G) {
635 node s1, s2;
636 return isTriconnected(G,s1,s2);
637 }
638
639
640 //! Returns true iff \p G is triconnected (using a quadratic time algorithm!).
641 /**
642 * @ingroup ga-connectivity
643 *
644 * If \p G is not triconnected then
645 * - \p s1 and \p s2 are both \c nullptr if \p G is not connected.
646 * - \p s1 is a cut vertex and \p s2 is \c nullptr if \p G is connected but not biconnected.
647 * - \p s1 and \p s2 are a separation pair if \p G is bi- but not triconnected.
648 *
649 * \warning This method has quadratic running time. An efficient linear time
650 * version is provided by isTriconnected().
651 *
652 * @param G is the input graph.
653 * @param s1 is assigned a cut vertex of one node of a separation pair, if \p G is not triconnected (see above).
654 * @param s2 is assigned one node of a separation pair, if \p G is not triconnected (see above).
655 * @return true if \p G is triconnected, false otherwise.
656 */
657 OGDF_EXPORT bool isTriconnectedPrimitive(const Graph &G, node &s1, node &s2);
658
659
660 //! Returns true iff \p G is triconnected (using a quadratic time algorithm!).
661 /**
662 * @ingroup ga-connectivity
663 *
664 * \warning This method has quadratic running time. An efficient linear time
665 * version is provided by isTriconnected().
666 *
667 * @param G is the input graph.
668 * @return true if \p G is triconnected, false otherwise.
669 */
isTriconnectedPrimitive(const Graph & G)670 inline bool isTriconnectedPrimitive(const Graph &G) {
671 node s1, s2;
672 return isTriconnectedPrimitive(G,s1,s2);
673 }
674
675
676 //! Triangulates a planarly embedded graph \p G by adding edges.
677 /**
678 * @ingroup ga-connectivity
679 *
680 * The result of this function is that \p G is made maximally planar by adding new edges.
681 * \p G will also be planarly embedded such that each face is a triangle.
682 *
683 * \pre \p G is planar, simple and represents a combinatorial embedding (i.e. \p G is planarly embedded).
684 *
685 * @param G is the input graph to which edges will be added.
686 */
687 void triangulate(Graph &G);
688
689
690 //! @}
691 //! \name Methods for directed graphs
692 //! @{
693
694 //! Returns true iff the digraph \p G is acyclic.
695 /**
696 * @ingroup ga-digraph
697 *
698 * @param G is the input graph
699 * @param backedges is assigned the backedges of a DFS-tree.
700 * @return true if \p G contains no directed cycle, false otherwise.
701 */
702 OGDF_EXPORT bool isAcyclic(const Graph &G, List<edge> &backedges);
703
704
705 //! Returns true iff the digraph \p G is acyclic.
706 /**
707 * @ingroup ga-digraph
708 *
709 * @param G is the input graph
710 * @return true if \p G contains no directed cycle, false otherwise.
711 */
isAcyclic(const Graph & G)712 inline bool isAcyclic(const Graph &G) {
713 List<edge> backedges;
714 return isAcyclic(G,backedges);
715 }
716
717
718 //! Returns true iff the undirected graph \p G is acyclic.
719 /**
720 * @ingroup ga-digraph
721 *
722 * @param G is the input graph
723 * @param backedges is assigned the backedges of a DFS-tree.
724 * @return true if \p G contains no undirected cycle, false otherwise.
725 */
726 OGDF_EXPORT bool isAcyclicUndirected(const Graph &G, List<edge> &backedges);
727
728
729 //! Returns true iff the undirected graph \p G is acyclic.
730 /**
731 * @ingroup ga-digraph
732 *
733 * @param G is the input graph
734 * @return true if \p G contains no undirected cycle, false otherwise.
735 */
isAcyclicUndirected(const Graph & G)736 inline bool isAcyclicUndirected(const Graph &G) {
737 List<edge> backedges;
738 return isAcyclicUndirected(G,backedges);
739 }
740
741
742 //! Makes the digraph \p G acyclic by removing edges.
743 /**
744 * @ingroup ga-digraph
745 *
746 * The implementation removes all backedges of a DFS tree.
747 *
748 * @param G is the input graph
749 */
750 OGDF_EXPORT void makeAcyclic(Graph &G);
751
752
753 //! Makes the digraph G acyclic by reversing edges.
754 /**
755 * @ingroup ga-digraph
756 *
757 * \remark The implementation ignores self-loops and reverses the backedges of a DFS-tree.
758 *
759 * @param G is the input graph
760 */
761 OGDF_EXPORT void makeAcyclicByReverse(Graph &G);
762
763
764 //! Returns true iff the digraph \p G contains exactly one source node (or is empty).
765 /**
766 * @ingroup ga-digraph
767 *
768 * @param G is the input graph.
769 * @param source is assigned the single source if true is returned, or 0 otherwise.
770 * @return true if \p G has a single source, false otherwise.
771 */
772 OGDF_EXPORT bool hasSingleSource(const Graph &G, node &source);
773
774
775 //! Returns true iff the digraph \p G contains exactly one source node (or is empty).
776 /**
777 * @ingroup ga-digraph
778 *
779 * @param G is the input graph.
780 * @return true if \p G has a single source, false otherwise.
781 */
hasSingleSource(const Graph & G)782 inline bool hasSingleSource(const Graph &G) {
783 node source;
784 return hasSingleSource(G,source);
785 }
786
787
788 //! Returns true iff the digraph \p G contains exactly one sink node (or is empty).
789 /**
790 * @ingroup ga-digraph
791 *
792 * @param G is the input graph.
793 * @param sink is assigned the single sink if true is returned, or 0 otherwise.
794 * @return true if \p G has a single sink, false otherwise.
795 */
796 OGDF_EXPORT bool hasSingleSink(const Graph &G, node &sink);
797
798
799 //! Returns true iff the digraph \p G contains exactly one sink node (or is empty).
800 /**
801 * @ingroup ga-digraph
802 *
803 * @param G is the input graph.
804 * @return true if \p G has a single sink, false otherwise.
805 */
hasSingleSink(const Graph & G)806 inline bool hasSingleSink(const Graph &G) {
807 node sink;
808 return hasSingleSink(G,sink);
809 }
810
811
812 //! Returns true iff \p G is an st-digraph.
813 /**
814 * @ingroup ga-digraph
815 *
816 * A directed graph is an st-digraph if it is acyclic, contains exactly one source s
817 * and one sink t, and the edge (s,t).
818 *
819 * @param G is the input graph.
820 * @param s is assigned the single source (if true is returned).
821 * @param t is assigned the single sink (if true is returned).
822 * @param st is assigned the edge (s,t) (if true is returned).
823 * @return true if \p G is an st-digraph, false otherwise.
824 */
825 OGDF_EXPORT bool isStGraph(const Graph &G, node &s, node &t, edge &st);
826
827
828 //! Returns true if \p G is an st-digraph.
829 /**
830 * @ingroup ga-digraph
831 *
832 * A directed graph is an st-digraph if it is acyclic, contains exactly one source s
833 * and one sink t, and the edge (s,t).
834 * @param G is the input graph.
835 * @return true if \p G is an st-digraph, false otherwise.
836 */
isStGraph(const Graph & G)837 inline bool isStGraph(const Graph &G) {
838 node s, t;
839 edge st;
840 return isStGraph(G,s,t,st);
841 }
842
843
844 //! Computes a topological numbering of an acyclic digraph \p G.
845 /**
846 * @ingroup ga-digraph
847 *
848 * \pre \p G is an acyclic directed graph.
849 *
850 * @param G is the input graph.
851 * @param num is assigned the topological numbering (0, 1, ...).
852 */
853 OGDF_EXPORT void topologicalNumbering(const Graph &G, NodeArray<int> &num);
854
855
856 //! Computes the strongly connected components of the digraph \p G.
857 /**
858 * @ingroup ga-connectivity
859 *
860 * The function implements the algorithm by Tarjan.
861 *
862 * @param G is the input graph.
863 * @param component is assigned a mapping from nodes to component numbers (0, 1, ...).
864 * @return the number of strongly connected components.
865 */
866 OGDF_EXPORT int strongComponents(const Graph& G, NodeArray<int>& component);
867
868
869 //! Makes the digraph \p G bimodal.
870 /**
871 * @ingroup ga-digraph
872 *
873 * The implementation splits all non-bimodal vertices into two vertices.
874 *
875 * @param G is the input graph.
876 * @param newEdges is the list containing the new edges.
877 *
878 */
879 OGDF_EXPORT void makeBimodal(Graph &G, List<edge> &newEdges);
880
881
882 //! Makes the digraph \p G bimodal.
883 /**
884 * @ingroup ga-digraph
885 *
886 * The implementation splits all non-bimodal vertices into two vertices.
887 *
888 * @param G is the input graph.
889 */
makeBimodal(Graph & G)890 inline void makeBimodal(Graph &G) {
891 List<edge> dummy;
892 makeBimodal(G, dummy);
893 }
894
895
896 //! @}
897 //! \name Methods for trees and forests
898 //! @{
899
900 OGDF_DEPRECATED("isAcyclicUndirected() should be used instead.")
901 /**
902 * @ingroup ga-tree
903 * @copydoc ogdf::isAcyclicUndirected(const Graph &G)
904 */
isFreeForest(const Graph & G)905 inline bool isFreeForest(const Graph &G) {
906 return isAcyclicUndirected(G);
907 }
908
909
910 //! Returns true iff \p G is a tree, i.e. contains no undirected cycle and is connected
911 /**
912 * @ingroup ga-tree
913 *
914 * @param G is the input graph.
915 * @return true if \p G is a tree, false otherwise.
916 */
isTree(const Graph & G)917 inline bool isTree(const Graph &G)
918 {
919 return G.empty() || ((G.numberOfNodes() == G.numberOfEdges() + 1) && isConnected(G));
920 }
921
922
923 //! Returns true iff \p G is a forest consisting only of arborescences.
924 /**
925 * @ingroup ga-tree
926 *
927 * @param G is the input graph.
928 * @param roots is assigned the list of root nodes of the arborescences in the forest.
929 * If false is returned, \p roots is undefined.
930 * @return true if \p G represents an arborescence forest, false otherwise.
931 */
932 OGDF_EXPORT bool isArborescenceForest(const Graph& G, List<node> &roots);
933
934
935 //! Returns true iff \p G is a forest consisting only of arborescences.
936 /**
937 * @ingroup ga-tree
938 *
939 * @param G is the input graph.
940 * @return true if \p G represents an arborescence forest, false otherwise.
941 */
isArborescenceForest(const Graph & G)942 inline bool isArborescenceForest(const Graph &G) {
943 List<node> roots;
944 return isArborescenceForest(G,roots);
945 }
946
947
948 OGDF_DEPRECATED("isArborescenceForest() should be used instead.")
949 /**
950 * @ingroup ga-tree
951 * @copydoc ogdf::isArborescenceForest(const Graph& G, List<node> &roots)
952 */
isForest(const Graph & G,List<node> & roots)953 inline bool isForest(const Graph& G, List<node> &roots) {
954 return isArborescenceForest(G, roots);
955 }
956
957
958 OGDF_DEPRECATED("isArborescenceForest() should be used instead.")
959 /**
960 * @ingroup ga-tree
961 * @copydoc ogdf::isArborescenceForest(const Graph& G)
962 */
isForest(const Graph & G)963 inline bool isForest(const Graph &G) {
964 return isArborescenceForest(G);
965 }
966
967
968 //! Returns true iff \p G represents an arborescence.
969 /**
970 * @ingroup ga-tree
971 *
972 * @param G is the input graph.
973 * @param root is assigned the root node (if true is returned).
974 * @return true if \p G represents an arborescence, false otherwise.
975 */
976 OGDF_EXPORT bool isArborescence(const Graph& G, node &root);
977
978
979 //! Returns true iff \p G represents an arborescence.
980 /**
981 * @ingroup ga-tree
982 *
983 * @param G is the input graph.
984 * @return true if \p G represents an arborescence, false otherwise.
985 */
isArborescence(const Graph & G)986 inline bool isArborescence(const Graph &G) {
987 node root;
988 return isArborescence(G,root);
989 }
990
991 //! @}
992
993 //! Checks if a graph is regular
994 /**
995 * @param G is the input graph.
996 * @return true if \p G is regular, false otherwise.
997 */
998 OGDF_EXPORT bool isRegular(const Graph& G);
999
1000
1001 //! Checks if a graph is d-regular
1002 /**
1003 * @param G is the input graph.
1004 * @param d is the vertex degree.
1005 * @return true if \p G is d-regular, false otherwise.
1006 */
1007 OGDF_EXPORT bool isRegular(const Graph& G, int d);
1008
1009
1010 //! Checks whether a graph is bipartite.
1011 /**
1012 * @param G is the input graph.
1013 * @param color is assigned the color for each node, i.e. the partition it
1014 * belongs to, if G is bipartite. Otherwise its contents are undefined.
1015 * @return true if \p G is bipartite, false otherwise.
1016 */
1017 OGDF_EXPORT bool isBipartite(const Graph &G, NodeArray<bool> &color);
1018
1019
1020 //! Checks whether a graph is bipartite.
1021 /**
1022 * @param G is the input graph.
1023 * @return true if \p G is bipartite, false otherwise.
1024 */
isBipartite(const Graph & G)1025 inline bool isBipartite(const Graph &G) {
1026 NodeArray<bool> color(G);
1027 return isBipartite(G, color);
1028 }
1029
1030 /**
1031 * Fills \p dist with the distribution given by a function \p func
1032 * in graph \p G.
1033 *
1034 * The array \p dist is initialized such that
1035 * \c dist.low() represents the minimum function value, and
1036 * \c dist.high() represents the maximum function value.
1037 *
1038 * The resulting \p dist array contains for each function value \a x
1039 * the number \a n of nodes that yield this function value \a x.
1040 * In that case, the value at index \a x of \p dist is \a n.
1041 * Also note that because \p dist is an array, all intermediate
1042 * values are 0.
1043 *
1044 * Examples:
1045 * - Getting the in-degree distribution:
1046 * \code
1047 * Array<int> indegDist;
1048 * nodeDistribution(G, indegDist, [](node v) { return v->indeg(); });
1049 * \endcode
1050 * - Getting the number of nodes belonging to specific connected components:
1051 * \code
1052 * NodeArray<int> component(G);
1053 * Array<int> compDist;
1054 * connectedComponents(G, component);
1055 * nodeDistribution(G, compDist, component);
1056 * \endcode
1057 *
1058 * @see ogdf::degreeDistribution
1059 */
1060 OGDF_EXPORT void nodeDistribution(const Graph& G, Array<int> °dist, std::function<int(node)> func);
1061
1062 /**
1063 * Fills \p degdist with the degree distribution of graph \p G.
1064 *
1065 * @see ogdf::nodeDistribution
1066 */
degreeDistribution(const Graph & G,Array<int> & degdist)1067 inline void degreeDistribution(const Graph& G, Array<int> °dist) {
1068 nodeDistribution(G, degdist, [](node v) {
1069 return v->degree();
1070 });
1071 }
1072
1073 }
1074