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 &parallelEdges)
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> &parallelEdges)
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 &parallelEdges) {
377 	makeParallelFreeUndirected(G, &parallelEdges);
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 &parallelEdges,
387 		EdgeArray<int> &cardPositive,
388 		EdgeArray<int> &cardNegative) {
389 	makeParallelFreeUndirected(G, &parallelEdges, &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> &degdist, 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> &degdist) {
1068 	nodeDistribution(G, degdist, [](node v) {
1069 		return v->degree();
1070 	});
1071 }
1072 
1073 }
1074