1 /** \file
2  * \brief Implementation of simple graph algorithms
3  *
4  * \author Carsten Gutwenger, 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 
33 #include <ogdf/basic/simple_graph_alg.h>
34 #include <ogdf/basic/GraphCopy.h>
35 #include <ogdf/basic/tuples.h>
36 #include <ogdf/basic/Math.h>
37 
38 namespace ogdf {
39 
40 // Functions related to self-loops
41 
removeSelfLoops(Graph & graph,node v)42 void removeSelfLoops(Graph &graph, node v) {
43 	adjEntry adj = v->firstAdj();
44 	adjEntry adjPrev = nullptr;
45 
46 	while (adj != nullptr) {
47 		edge e{adj->theEdge()};
48 		if (e->isSelfLoop()) {
49 			graph.delEdge(e);
50 		} else {
51 			adjPrev = adj;
52 		}
53 
54 		adj = adjPrev == nullptr ? v->firstAdj() : adjPrev->succ();
55 	}
56 }
57 
isLoopFree(const Graph & G)58 bool isLoopFree(const Graph &G)
59 {
60 	for(edge e : G.edges)
61 		if(e->isSelfLoop()) return false;
62 
63 	return true;
64 }
65 
makeLoopFree(Graph & G)66 void makeLoopFree(Graph &G)
67 {
68 	safeForEach(G.edges, [&](edge e) {
69 		if (e->isSelfLoop()) G.delEdge(e);
70 	});
71 }
72 
hasNonSelfLoopEdges(const Graph & G)73 bool hasNonSelfLoopEdges(const Graph &G) {
74 	for (edge e : G.edges) {
75 		if (!e->isSelfLoop()) {
76 			return true;
77 		}
78 	}
79 	return false;
80 }
81 
82 // Functions related to directed parallel edges
83 
parallelFreeSort(const Graph & G,SListPure<edge> & edges)84 void parallelFreeSort(const Graph &G, SListPure<edge> &edges)
85 {
86 	G.allEdges(edges);
87 
88 	BucketSourceIndex bucketSrc;
89 	edges.bucketSort(0,G.maxNodeIndex(),bucketSrc);
90 
91 	BucketTargetIndex bucketTgt;
92 	edges.bucketSort(0,G.maxNodeIndex(),bucketTgt);
93 }
94 
isParallelFree(const Graph & G)95 bool isParallelFree(const Graph &G) {
96 	return numParallelEdges<true>(G) == 0;
97 }
98 
99 // Functions related to undirected parallel edges
100 
parallelFreeSortUndirected(const Graph & G,SListPure<edge> & edges,EdgeArray<int> & minIndex,EdgeArray<int> & maxIndex)101 void parallelFreeSortUndirected(const Graph &G,
102 	SListPure<edge> &edges,
103 	EdgeArray<int> &minIndex,
104 	EdgeArray<int> &maxIndex)
105 {
106 	G.allEdges(edges);
107 
108 	for(edge e : G.edges) {
109 		int srcIndex = e->source()->index(), tgtIndex = e->target()->index();
110 		if (srcIndex <= tgtIndex) {
111 			minIndex[e] = srcIndex; maxIndex[e] = tgtIndex;
112 		} else {
113 			minIndex[e] = tgtIndex; maxIndex[e] = srcIndex;
114 		}
115 	}
116 
117 	BucketEdgeArray bucketMin(minIndex), bucketMax(maxIndex);
118 	edges.bucketSort(0,G.maxNodeIndex(),bucketMin);
119 	edges.bucketSort(0,G.maxNodeIndex(),bucketMax);
120 }
121 
isParallelFreeUndirected(const Graph & G)122 bool isParallelFreeUndirected(const Graph &G) {
123 	return numParallelEdgesUndirected<true>(G) == 0;
124 }
125 
126 // Testing and establishing connectivity
127 
isConnected(const Graph & G)128 bool isConnected(const Graph &G)
129 {
130 	node v = G.firstNode();
131 	if (v == nullptr) return true;
132 
133 	int count = 0;
134 	NodeArray<bool> visited(G,false);
135 	ArrayBuffer<node> S(G.numberOfNodes());
136 
137 	S.push(v);
138 	visited[v] = true;
139 	while(!S.empty()) {
140 		v = S.popRet();
141 		++count;
142 
143 		for(adjEntry adj : v->adjEntries) {
144 			node w = adj->twinNode();
145 			if(!visited[w]) {
146 				visited[w] = true;
147 				S.push(w);
148 			}
149 		}
150 	}
151 
152 	return count == G.numberOfNodes();
153 }
154 
155 
makeConnected(Graph & G,List<edge> & added)156 void makeConnected(Graph &G, List<edge> &added)
157 {
158 	added.clear();
159 	if (G.numberOfNodes() == 0) return;
160 	NodeArray<bool> visited(G,false);
161 	ArrayBuffer<node> S(G.numberOfNodes());
162 
163 	node pred = nullptr;
164 	for(node u : G.nodes)
165 	{
166 		if (visited[u]) continue;
167 
168 		node vMinDeg = u;
169 		int  minDeg  = u->degree();
170 
171 		S.push(u);
172 		visited[u] = true;
173 
174 		while(!S.empty())
175 		{
176 			node v = S.popRet();
177 
178 			for(adjEntry adj : v->adjEntries) {
179 				node w = adj->twinNode();
180 				if(!visited[w]) {
181 					visited[w] = true;
182 					S.push(w);
183 
184 					int wDeg = w->degree();
185 					if (wDeg < minDeg) {
186 						vMinDeg = w;
187 						minDeg  = wDeg;
188 					}
189 				}
190 			}
191 		}
192 
193 		if (pred)
194 			added.pushBack(G.newEdge(pred,vMinDeg));
195 		pred = vMinDeg;
196 	}
197 }
198 
199 
connectedComponents(const Graph & G,NodeArray<int> & component,List<node> * isolated)200 int connectedComponents(const Graph &G,
201 		NodeArray<int> &component,
202 		List<node> *isolated)
203 {
204 	int nComponent = 0;
205 	component.fill(-1);
206 
207 	ArrayBuffer<node> S;
208 
209 	for(node v : G.nodes) {
210 		if (component[v] != -1) continue;
211 
212 		if (isolated != nullptr && v->degree() == 0) {
213 			isolated->pushBack(v);
214 		}
215 		S.push(v);
216 		component[v] = nComponent;
217 
218 		while(!S.empty()) {
219 			node w = S.popRet();
220 			for(adjEntry adj : w->adjEntries) {
221 				node x = adj->twinNode();
222 				if (component[x] == -1) {
223 					component[x] = nComponent;
224 					S.push(x);
225 				}
226 			}
227 		}
228 
229 		++nComponent;
230 	}
231 
232 	return nComponent;
233 }
234 
235 // Testing and establishing biconnectivity
236 
237 //! Build up a dfs-tree starting from the node root by assigning each reachable
238 //! node in the graph a discovery time (number) and a parent.
239 /**
240  * @param root is the node which should be the root of the dfs-tree.
241  * @param number is assigned the number (discovery time) for each node.
242  *        The number of root is firstNr, the number of unvisited nodes is 0.
243  * @param parent is assigned the parent in the dfs-tree for each node.
244  * @param childNr is assigned the number of children for each node.
245  * @param revS is assigned all visited nodes such that the top element of revS
246  *        is the node that was visited last.
247  * @param directed should be set to true if the directionality of edges should
248  *        be respected.
249  * @param firstNr is the index > 0 at which the numbering of the nodes starts.
250  * @return the number of visited nodes, i.e., nodes in the dfs-tree.
251  */
buildDfsTree(const node & root,NodeArray<int> & number,NodeArray<node> & parent,NodeArray<int> & childNr,ArrayBuffer<node> & revS,bool directed=false,int firstNr=1)252 static int buildDfsTree(const node &root,
253 		NodeArray<int> &number,
254 		NodeArray<node> &parent,
255 		NodeArray<int> &childNr,
256 		ArrayBuffer<node> &revS,
257 		bool directed = false,
258 		int firstNr = 1)
259 {
260 	OGDF_ASSERT(firstNr > 0);
261 
262 	ArrayBuffer<node> S;
263 	S.push(root);
264 
265 	int numCount = firstNr;
266 	childNr.fill(0);
267 
268 	// Build up search tree and note discovery time and parent for each node.
269 	while (!S.empty()) {
270 		node v = S.popRet();
271 
272 		// Ignore nodes that were already visited.
273 		if (number[v] != 0) {
274 			continue;
275 		}
276 
277 		revS.push(v);
278 
279 		// Set correct discovery time for v.
280 		number[v] = numCount++;
281 
282 		// For all adjacent nodes w of v:
283 		for (adjEntry adj : v->adjEntries) {
284 			if (directed && adj->theEdge()->source() != v) {
285 				continue;
286 			}
287 
288 			node w = adj->twinNode();
289 
290 			// If w has not been visited yet:
291 			// Push it on the stack, remember its parent and number of children.
292 			if (number[w] == 0) {
293 				S.push(w);
294 
295 				// If a parent was determined previously, revert that.
296 				if (parent[w] != nullptr) {
297 					childNr[parent[w]]--;
298 				}
299 
300 				parent[w] = v;
301 				childNr[v]++;
302 			}
303 		}
304 	}
305 
306 	return numCount - firstNr;
307 }
308 
309 //! Find cut vertices and potential edges that could be added to turn the cut
310 //! vertices into non-cut vertices.
311 /**
312  * The algorithm is applied to the graph whose nodes were pushed to the
313  * ArrayBuffer revS. number, parent and revS can be obtained with buildDfsTree.
314  *
315  * @param number contains the number (discovery time) for each node.
316  *        The number of root is 1, the number of unvisited nodes is 0.
317  * @param parent contains the parent in the dfs-tree for each node.
318  * @param revS contains the nodes of a graph such that the node that was visited
319  *        last during the dfs-traversal is its top element.
320  * @param cutVertices is assigned the cut vertices of the graph.
321  * @param addEdges is assigned the tuples of nodes which have to be connected in
322  *        order to turn each cut vertex into a non-cut vertex.
323  * @param only_one should be set to true if the search should stop after finding
324  *        one cut vertex, to false if all cut vertices should be found.
325  * @return true if the graph contains at least one cut vertex, false otherwise.
326  */
findCutVertices(NodeArray<int> & number,NodeArray<node> & parent,ArrayBuffer<node> & revS,ArrayBuffer<node> & cutVertices,ArrayBuffer<Tuple2<node,node>> & addEdges,bool only_one)327 static bool findCutVertices(NodeArray<int> &number,
328 		NodeArray<node> &parent,
329 		ArrayBuffer<node> &revS,
330 		ArrayBuffer<node> &cutVertices,
331 		ArrayBuffer<Tuple2<node,node>> &addEdges,
332 		bool only_one)
333 {
334 	NodeArray<int> lowpt(number);
335 
336 	// Go backwards through the dfs-tree:
337 	// Calculate the lowpoint for each node and test for cut vertices.
338 	while (!revS.empty()) {
339 		node v = revS.popRet();
340 		node firstChild = nullptr;
341 
342 		// For all adjacent nodes w of v:
343 		for (adjEntry adj : v->adjEntries) {
344 			node w = adj->twinNode();
345 
346 			// Ignore self-loops and the parent of v.
347 			if (v == w || parent[v] == w) {
348 				continue;
349 			}
350 
351 			// If v->w is a backedge in the dfs-tree, update v's lowpoint.
352 			if (number[v] > number[w] ) {
353 				if (lowpt[v] > number[w]) {
354 					lowpt[v] = number[w];
355 				}
356 			} else {
357 				// If w is v's child in the dfs-tree, update v's lowpoint.
358 				if (parent[w] == v) {
359 					if (lowpt[v] > lowpt[w]) {
360 						lowpt[v] = lowpt[w];
361 					}
362 
363 					// See whether w is v's first son.
364 					if (firstChild == nullptr) {
365 						firstChild = w;
366 					}
367 
368 					// Non-root v is a cut vertex if lowpt[w] >= number[v].
369 					if (parent[v] != nullptr && lowpt[w] >= number[v]) {
370 						// Suggest to add an edge between w and v's parent.
371 						cutVertices.push(v);
372 						addEdges.push(Tuple2<node,node>(w, parent[v]));
373 
374 						if (only_one) {
375 							return true;
376 						}
377 					}
378 
379 					// Root v is a cut vertex if v has two or more children.
380 					if  (parent[v] == nullptr && w != firstChild) {
381 						// Suggest to add an edge between those children.
382 						cutVertices.push(v);
383 						addEdges.push(Tuple2<node,node>(w, firstChild));
384 
385 						if (only_one) {
386 							return true;
387 						}
388 					}
389 				}
390 			}
391 		}
392 	}
393 
394 	return !cutVertices.empty();
395 }
396 
isBiconnected(const Graph & G,node & cutVertex)397 bool isBiconnected(const Graph &G, node &cutVertex)
398 {
399 	cutVertex = nullptr;
400 
401 	if (G.empty()) {
402 		return true;
403 	}
404 
405 	NodeArray<int> number(G,0);        // discovery times
406 	NodeArray<node> parent(G,nullptr); // parents in the dfs tree
407 	ArrayBuffer<node> revS;            // nodes of the dfs tree in reverse order
408 
409 	// Build the dfs-tree and get the number of visited nodes.
410 	NodeArray<int> childNr(G);
411 	int numCount = buildDfsTree(G.firstNode(), number, parent, childNr, revS);
412 
413 	// If the graph is not connected, return false.
414 	if (numCount != G.numberOfNodes()) {
415 		return false;
416 	}
417 
418 	// If there are cut vertices in the graph, return false, else true.
419 	ArrayBuffer<node> cutVertices;
420 	ArrayBuffer<Tuple2<node,node>> addEdges;
421 	if (findCutVertices(number, parent, revS, cutVertices, addEdges, true)) {
422 		cutVertex = cutVertices.top();
423 		return false;
424 	} else {
425 		return true;
426 	}
427 }
428 
makeBiconnected(Graph & G,List<edge> & added)429 void makeBiconnected(Graph &G, List<edge> &added)
430 {
431 	if (G.empty()) {
432 		return;
433 	}
434 
435 	makeConnected(G, added);
436 
437 	NodeArray<int> number(G,0);        // discovery times
438 	NodeArray<node> parent(G,nullptr); // parents in the dfs tree
439 	ArrayBuffer<node> revS;            // nodes of the dfs tree in reverse order
440 
441 	// Build the dfs-tree.
442 	NodeArray<int> childNr(G);
443 	buildDfsTree(G.firstNode(), number, parent, childNr, revS);
444 
445 	// Find all cut vertices.
446 	ArrayBuffer<node> cutVertices;
447 	ArrayBuffer<Tuple2<node,node>> addEdges;
448 	findCutVertices(number, parent, revS, cutVertices, addEdges, false);
449 
450 	// Add a new edge for each cut vertex to make the graph biconnected.
451 	for (Tuple2<node,node> nodes : addEdges) {
452 		added.pushBack(G.newEdge(nodes.x1(), nodes.x2()));
453 	}
454 }
455 
456 
457 // Biconnected components
458 
459 /**
460  * Return true iff all incident edges of the given node v are self-loops.
461  * In particular, return true if v has no incident edges at all.
462  *
463  * @param v the node to be tested for isolation.
464  * @return true iff v has no incident edges to other nodes.
465  */
isIsolated(const node v)466 static bool isIsolated(const node v)
467 {
468 	bool isolated = true;
469 	for (adjEntry adj : v->adjEntries) {
470 		if (adj->twinNode() != v) {
471 			isolated = false;
472 			break;
473 		}
474 	}
475 
476 	return isolated;
477 }
478 
biconnectedComponents(const Graph & G,EdgeArray<int> & component,int & nComponent)479 int biconnectedComponents(const Graph &G, EdgeArray<int> &component, int &nComponent)
480 {
481 	if (G.empty()) {
482 		return 0;
483 	}
484 
485 	NodeArray<int> number(G,0);      // discovery times
486 	NodeArray<int> lowpt(G);         // lowpoints
487 	ArrayBuffer<node> called;        // already visited nodes
488 
489 	int nNumber = 0;                 // number of nodes
490 	int nIsolated = 0;               // number of isolated nodes
491 	nComponent = 0;                  // number of biconnected components
492 
493 	// For every unvisited node u:
494 	for(node u : G.nodes) {
495 		if (number[u] != 0) {
496 			continue;
497 		}
498 
499 		if (isIsolated(u)) {
500 			++nIsolated;
501 		}
502 
503 		// We have to simulate the call stack to turn the normally recursive
504 		// algorithm into an iterative one. A struct for our stack variables:
505 		struct StackElem {
506 			node v;
507 			node parent;
508 			ListPure<adjEntry> *adjEntries;
509 
510 			StackElem() {}
511 			StackElem(node vertex, node father) : v(vertex), parent(father) {
512 				adjEntries = new ListPure<adjEntry>;
513 				vertex->allAdjEntries(*adjEntries);
514 			}
515 		} initElem = {u, nullptr};
516 
517 		// Start a depth-first search at u.
518 		ArrayBuffer<StackElem> stack;
519 		stack.push(initElem);
520 		bool forwards = true;
521 
522 		while (!stack.empty()) {
523 			bool restartLoop = false;
524 
525 			// Get current node, parent and adjEntries from the stack.
526 			StackElem elem = stack.top();
527 			node v = elem.v;
528 			node parent = elem.parent;
529 			ListPure<adjEntry> *adjEntries = elem.adjEntries;
530 
531 			// If we are continuing the dfs forwards and have a new node:
532 			// Note discovery time & initial lowpoint, remember v for later.
533 			if (forwards) {
534 				lowpt[v] = number[v] = ++nNumber;
535 				called.push(v);
536 			} else {
537 				// If backtracking, update v's lowpt using its visited child w.
538 				node w = adjEntries->popFrontRet()->twinNode();
539 				if (lowpt[w] < lowpt[v]) {
540 					lowpt[v] = lowpt[w];
541 				}
542 			}
543 
544 			// For all adjacent nodes w of v:
545 			while (!adjEntries->empty() && !restartLoop) {
546 				node w = adjEntries->front()->twinNode();
547 
548 				// If w is unvisited, continue the dfs with w & v as its parent.
549 				if (number[w] == 0) {
550 					stack.push(StackElem(w,v));
551 					forwards = true;
552 					restartLoop = true;
553 				} else {
554 					if (v == w) {
555 						// Put self-loops in their own biconnected components.
556 						if (adjEntries->front()->isSource()) {
557 							component[adjEntries->front()->theEdge()] = nComponent++;
558 						}
559 					} else {
560 						// Else update v's lowpoint.
561 						if (number[w] < lowpt[v]) {
562 							lowpt[v] = number[w];
563 						}
564 					}
565 					adjEntries->popFront();
566 				}
567 			}
568 
569 			if (restartLoop) {
570 				continue;
571 			}
572 
573 			// If the parent of v is a cut vertex:
574 			// The upwards-going edges of all the nodes below that parent in the
575 			// dfs-tree form one biconnected component.
576 			if (parent != nullptr && lowpt[v] == number[parent]) {
577 				node w;
578 				do {
579 					w = called.popRet();
580 					for (adjEntry adj : w->adjEntries) {
581 						if (number[w] > number[adj->twinNode()]) {
582 							component[adj->theEdge()] = nComponent;
583 						}
584 					}
585 				} while (w != v);
586 				++nComponent;
587 			}
588 
589 			// v has no more children to visit. Backtrack.
590 			stack.pop();
591 			forwards = false;
592 			delete adjEntries;
593 		}
594 	}
595 
596 	return nComponent + nIsolated;
597 }
598 
599 /**
600  * Helper function for ogdf::isTwoEdgeConnected
601  * Fills up the output parameters \p dfsOrder, \p prev and \p backEdges, by doing a dfs on the \p graph.
602  *
603  * @param graph input graph
604  * @param dfsOrder the nodes of the graph get pushed into this list
605  * in the order in which they appear in the DFS
606  * @param prev maps to the edge from which a node was entered in the DFS
607  * @param backEdges list all backedges of a node
608  * @return false, if the \p graph is not connected, true otherwise
609  */
dfsTwoEdgeConnected(const Graph & graph,List<node> & dfsOrder,NodeArray<edge> & prev,NodeArray<ArrayBuffer<edge>> & backEdges)610 static bool dfsTwoEdgeConnected(const Graph &graph,
611                                 List<node> &dfsOrder,
612                                 NodeArray<edge> &prev,
613                                 NodeArray<ArrayBuffer<edge>> &backEdges)
614 {
615 	dfsOrder.clear();
616 	prev.init(graph, nullptr);
617 	backEdges.init(graph, ArrayBuffer<edge>());
618 	EdgeArray<bool> visited(graph, false);
619 
620 	struct StackElement {
621 		node v;
622 		edge e; // edge to v
623 	};
624 	ArrayBuffer<StackElement> stack;
625 	int visitCounter = 0;
626 
627 	auto push = [&](node vPush, edge ignoredEdge){
628 		visitCounter++;
629 		dfsOrder.pushBack(vPush);
630 		for(adjEntry adj : vPush->adjEntries) {
631 			if(adj->theEdge() != ignoredEdge && !visited[adj->theEdge()]) {
632 				stack.push(StackElement{adj->twinNode(), adj->theEdge()});
633 			}
634 		}
635 	};
636 	push(graph.firstNode(), nullptr);
637 
638 	while(stack.size() != 0) {
639 		StackElement currentElem = stack.popRet();
640 		node current = currentElem.v;
641 		edge prevEdge = currentElem.e;
642 		if(visited[prevEdge]) {
643 			continue;
644 		}
645 		visited[prevEdge] = true;
646 		if(prev[current] != nullptr || current == graph.firstNode()) {
647 			backEdges[current].push(prevEdge);
648 		} else {
649 			prev[current] = prevEdge;
650 			push(current, prevEdge);
651 		}
652 	}
653 
654 	return visitCounter == graph.numberOfNodes();
655 }
656 
657 /**
658  * Helper function for ogdf::isTwoEdgeConnected
659  *
660  * @copydetails ogdf::dfsTwoEdgeConnected
661  * @param bridge same as in ogdf::isTwoEdgeConnected
662  */
chainsTwoEdgeConnected(const Graph & graph,edge & bridge,List<node> & dfsOrder,const NodeArray<edge> & prev,const NodeArray<ArrayBuffer<edge>> & backEdges)663 static bool chainsTwoEdgeConnected(const Graph &graph,
664                                    edge &bridge,
665                                    List<node> &dfsOrder,
666                                    const NodeArray<edge> &prev,
667                                    const NodeArray<ArrayBuffer<edge>> &backEdges)
668 {
669 	NodeArray<bool> visited(graph, false);
670 	EdgeArray<bool> inAChain(graph, false);
671 
672 	while(!dfsOrder.empty()) {
673 		node current = dfsOrder.popFrontRet();
674 		for(edge e : backEdges[current]) {
675 			inAChain[e] = true;
676 			visited[current] = true;
677 			node v = e->opposite(current);
678 			while(!visited[v]) {
679 				visited[v] = true;
680 				edge prevEdge = prev[v];
681 				if(prevEdge != nullptr) {
682 					v = prevEdge->opposite(v);
683 					inAChain[prevEdge] = true;
684 				}
685 			}
686 		}
687 	}
688 
689 	for(edge e : graph.edges) {
690 		if(!inAChain[e]){
691 			bridge = e;
692 			// bridge found
693 			return false;
694 		}
695 	}
696 
697 	return true;
698 }
699 
isTwoEdgeConnected(const Graph & graph,edge & bridge)700 bool isTwoEdgeConnected(const Graph &graph, edge &bridge) {
701 	bridge = nullptr;
702 	NodeArray<edge> prev(graph, nullptr);
703 	NodeArray<ArrayBuffer<edge>> backEdges(graph, ArrayBuffer<edge>());
704 	List<node> dfsOrder;
705 
706 	if(graph.numberOfNodes() <= 1) {
707 		// empty and single-node graphs are defined to be 2-edge-connected
708 		return true;
709 	}
710 
711 	if(!dfsTwoEdgeConnected(graph, dfsOrder, prev, backEdges)) {
712 		// not connected
713 		return false;
714 	}
715 
716 	return chainsTwoEdgeConnected(graph, bridge, dfsOrder, prev, backEdges);
717 }
718 
719 // Testing triconnectivity
720 
isTriconnectedPrimitive(const Graph & G,node & s1,node & s2)721 bool isTriconnectedPrimitive(const Graph &G, node &s1, node &s2)
722 {
723 	s1 = s2 = nullptr;
724 
725 	if (!isConnected(G) || !isBiconnected(G, s1)) {
726 		return false;
727 	}
728 
729 	if (G.numberOfNodes() <= 3)
730 		return true;
731 
732 	// make a copy of G
733 	GraphCopySimple GC(G);
734 
735 	// for each node v in G, we test if G \ v is biconnected
736 	for(node v : G.nodes)
737 	{
738 		node vC = GC.copy(v), wC;
739 
740 		// store adjacent nodes
741 		SListPure<node> adjacentNodes;
742 		for(adjEntry adj : vC->adjEntries) {
743 			wC = adj->twinNode();
744 			// forget self-loops (vC would no longer be in GC!)
745 			if (wC != vC)
746 				adjacentNodes.pushBack(wC);
747 		}
748 
749 		GC.delNode(vC);
750 
751 		// test for biconnectivity
752 		if(!isBiconnected(GC, wC)) {
753 			s1 = v; s2 = GC.original(wC);
754 			return false;
755 		}
756 
757 		// restore deleted node with adjacent edges
758 		vC = GC.newNode(v);
759 		for(node uC : adjacentNodes)
760 			GC.newEdge(vC,uC);
761 	}
762 
763 	return true;
764 }
765 
766 
767 // Triangulations
768 
triangulate(Graph & G)769 void triangulate(Graph &G)
770 {
771 	OGDF_ASSERT(isSimple(G));
772 
773 	CombinatorialEmbedding E(G);
774 
775 #ifdef OGDF_DEBUG
776 	E.consistencyCheck();
777 #endif
778 
779 	adjEntry succ, succ2, succ3;
780 	NodeArray<int> marked(E.getGraph(), 0);
781 
782 	for(node v : E.getGraph().nodes) {
783 		marked.init(E.getGraph(), 0);
784 
785 		for(adjEntry adj : v->adjEntries) {
786 			marked[adj->twinNode()] = 1;
787 		}
788 
789 		// forall faces adj to v
790 		for(adjEntry adj : v->adjEntries) {
791 			succ = adj->faceCycleSucc();
792 			succ2 = succ->faceCycleSucc();
793 
794 			if (succ->twinNode() != v && adj->twinNode() != v) {
795 				while (succ2->twinNode() != v) {
796 					if (marked[succ2->theNode()] == 1) {
797 						// edge e=(x2,x4)
798 						succ3 = succ2->faceCycleSucc();
799 						E.splitFace(succ, succ3);
800 					}
801 					else {
802 						// edge e=(v=x1,x3)
803 						edge e = E.splitFace(adj, succ2);
804 						marked[succ2->theNode()] = 1;
805 
806 						// old adj is in wrong face
807 						adj = e->adjSource();
808 					}
809 					succ = adj->faceCycleSucc();
810 					succ2 = succ->faceCycleSucc();
811 				}
812 			}
813 		}
814 	}
815 }
816 
817 
818 // Testing and establishing acyclicity
819 
isAcyclic(const Graph & G,List<edge> & backedges)820 bool isAcyclic(const Graph &G, List<edge> &backedges)
821 {
822 	backedges.clear();
823 
824 	NodeArray<int> number(G,0);        // discovery times
825 	NodeArray<node> parent(G,nullptr); // parents in the dfs tree
826 	NodeArray<int> childNr(G);         // number of children in the dfs tree
827 	ArrayBuffer<node> revS;
828 
829 	ArrayBuffer<node> leaves;          // leaves of the dfs tree
830 	NodeArray<int> completion(G,0);    // completion times
831 	int complCount = 0;
832 	int numCount = 0;
833 
834 	// For all unvisited nodes:
835 	for (node v : G.nodes) {
836 		if (number[v] == 0) {
837 			// Build the dfs-tree starting at v.
838 			numCount += buildDfsTree(v, number, parent, childNr, revS, true, numCount+1);
839 
840 			// Get all leaves of the dfs-tree.
841 			while (!revS.empty()) {
842 				node w = revS.popRet();
843 				if (childNr[w] == 0) {
844 					leaves.push(w);
845 				}
846 			}
847 
848 			node lastParent = parent[leaves.top()];
849 
850 			// Go through leaves of the dfs-tree.
851 			while (!leaves.empty()) {
852 				node w = leaves.top();
853 
854 				// If the new leaf is a child of the same parent as before,
855 				// assign it a completion time and pop it from the stack.
856 				if (parent[w] == lastParent) {
857 					completion[w] = complCount++;
858 					leaves.pop();
859 
860 					// The last parent has now one child less. If it has no
861 					// children anymore, push it as a new leaf on the stack.
862 					if (lastParent != nullptr) {
863 						childNr[lastParent]--;
864 						if (childNr[lastParent] == 0) {
865 							leaves.push(lastParent);
866 							lastParent = parent[lastParent];
867 						}
868 					}
869 				} else {
870 					// Else just continue with the next leaves and their parent.
871 					lastParent = parent[w];
872 				}
873 			}
874 		}
875 	}
876 
877 	// Remember backedges.
878 	for(edge e : G.edges) {
879 		node src = e->source();
880 		node tgt = e->target();
881 
882 		if (number[src] >= number[tgt] && completion[src] <= completion[tgt]) {
883 			backedges.pushBack(e);
884 		}
885 	}
886 
887 	return backedges.empty();
888 }
889 
890 
isAcyclicUndirected(const Graph & G,List<edge> & backedges)891 bool isAcyclicUndirected(const Graph &G, List<edge> &backedges)
892 {
893 	backedges.clear();
894 
895 	NodeArray<int> number(G,0);        // discovery times
896 	NodeArray<node> parent(G,nullptr); // parents in the dfs tree
897 	ArrayBuffer<node> S;
898 	int numCount = 0;
899 
900 	// For all unvisited nodes:
901 	for (node v : G.nodes) {
902 		if (number[v] == 0) {
903 			// Start depth first search at v.
904 			S.push(v);
905 			while (!S.empty()) {
906 				node w = S.popRet();
907 
908 				// Ignore nodes that were already visited.
909 				if (number[w] != 0) {
910 					continue;
911 				}
912 
913 				// Set correct discovery time for w.
914 				number[w] = ++numCount;
915 				bool parentSeen = false;
916 
917 				// For all adjacent nodes u of w:
918 				for (adjEntry adj : w->adjEntries) {
919 					node u = adj->twinNode();
920 
921 					// If u has not been visited yet,
922 					// push it on the stack and remember its parent.
923 					if (number[u] == 0) {
924 						S.push(u);
925 						parent[u] = w;
926 					} else if (parent[w] == u && !parentSeen) {
927 						// The first time you see w's parent, it is no backedge.
928 						parentSeen = true;
929 					} else if (w != u || adj->isSource()) {
930 						// Collect backedges (self-loops only in one direction).
931 						backedges.pushBack(adj->theEdge());
932 					}
933 				}
934 			}
935 		}
936 	}
937 
938 	return backedges.empty();
939 }
940 
941 
makeAcyclic(Graph & G)942 void makeAcyclic(Graph &G)
943 {
944 	List<edge> backedges;
945 	isAcyclic(G,backedges);
946 
947 	for(edge e : backedges)
948 		G.delEdge(e);
949 }
950 
951 
makeAcyclicByReverse(Graph & G)952 void makeAcyclicByReverse(Graph &G)
953 {
954 	List<edge> backedges;
955 	isAcyclic(G,backedges);
956 
957 	for(edge e : backedges)
958 		if (!e->isSelfLoop()) G.reverseEdge(e);
959 }
960 
961 
962 // Testing sources and sinks
963 
hasSingleSource(const Graph & G,node & s)964 bool hasSingleSource(const Graph& G, node &s)
965 {
966 	s = nullptr;
967 
968 	for(node v : G.nodes) {
969 		if (v->indeg() == 0) {
970 			if (s != nullptr) {
971 				s = nullptr;
972 				return false;
973 			} else s = v;
974 		}
975 	}
976 	return G.empty() || s != nullptr;
977 }
978 
979 
hasSingleSink(const Graph & G,node & t)980 bool hasSingleSink(const Graph& G, node &t)
981 {
982 	t = nullptr;
983 
984 	for(node v : G.nodes) {
985 		if (v->outdeg() == 0) {
986 			if (t != nullptr) {
987 				t = nullptr;
988 				return false;
989 			} else t = v;
990 		}
991 	}
992 	return G.empty() || t != nullptr;
993 }
994 
995 
996 // isStGraph()
997 // true <=> G is st-graph, i.e., is acyclic, contains exactly one source s
998 //   and one sink t, and the edge (s,t); returns single source s and single
999 //   sink t if contained (otherwise they are set to 0), and edge st if
1000 //   contained (otherwise 0)
isStGraph(const Graph & G,node & s,node & t,edge & st)1001 bool isStGraph(const Graph &G, node &s, node &t, edge &st)
1002 {
1003 	st = nullptr;
1004 
1005 	hasSingleSource(G,s);
1006 	hasSingleSink  (G,t);
1007 
1008 	if (s == nullptr || t == nullptr || !isAcyclic(G)) {
1009 		s = t = nullptr;
1010 		return false;
1011 	}
1012 
1013 	for(adjEntry adj : s->adjEntries) {
1014 		edge e = adj->theEdge();
1015 
1016 		if (e->target() == t) {
1017 			st = e;
1018 			break;
1019 		}
1020 	}
1021 
1022 	return st != nullptr;
1023 }
1024 
1025 
1026 // Topological numbering in acyclic graphs
1027 
topologicalNumbering(const Graph & G,NodeArray<int> & num)1028 void topologicalNumbering(const Graph &G, NodeArray<int> &num)
1029 {
1030 	ArrayBuffer<node> S(G.numberOfNodes());
1031 	NodeArray<int> indeg(G);
1032 
1033 	for(node v : G.nodes)
1034 		if((indeg[v] = v->indeg()) == 0)
1035 			S.push(v);
1036 
1037 	int count = 0;
1038 	while(!S.empty()) {
1039 		node v = S.popRet();
1040 		num[v] = count++;
1041 
1042 		for(adjEntry adj : v->adjEntries) {
1043 			node u = adj->theEdge()->target();
1044 			if (u != v && --indeg[u] == 0) {
1045 				S.push(u);
1046 			}
1047 		}
1048 	}
1049 }
1050 
strongComponents(const Graph & graph,NodeArray<int> & components)1051 int strongComponents(const Graph &graph, NodeArray<int> &components)
1052 {
1053 	int nNodes = graph.numberOfNodes();
1054 
1055 	if (nNodes == 0) {
1056 		return 0;
1057 	}
1058 
1059 	// A node v is on the stack set iff index[v] > -1 and lowLinks[v] < nNodes.
1060 	NodeArray<int> lowLinks(graph, -1);
1061 	NodeArray<int> index(graph, -1);
1062 	ArrayBuffer<node> set(nNodes);
1063 	int nextIndex = 0;
1064 	int result = 0;
1065 
1066 	// For every unvisited node u:
1067 	for (node u : graph.nodes) {
1068 		if (index[u] == -1) {
1069 			// We have to simulate the call stack to turn the normally recursive
1070 			// algorithm into an iterative one. A struct for our stack variables:
1071 			struct StackElem {
1072 				node v;
1073 				ListPure<edge> *outEdges;
1074 
1075 				StackElem() = default;
1076 				explicit StackElem(node vertex) : v(vertex) {
1077 					outEdges = new ListPure<edge>;
1078 					vertex->outEdges(*outEdges);
1079 				}
1080 			} initElem = StackElem(u);
1081 
1082 			// Start a depth-first search at u.
1083 			ArrayBuffer<StackElem> stack;
1084 			stack.push(initElem);
1085 			bool forwards = true;
1086 
1087 			while (!stack.empty()) {
1088 				bool restartLoop = false;
1089 
1090 				// Get current node and outEdges from the stack.
1091 				StackElem elem = stack.top();
1092 				node v = elem.v;
1093 				ListPure<edge> *outEdges = elem.outEdges;
1094 
1095 				// If we are continuing the dfs forwards and have a new node v:
1096 				// Note v's index & initial lowlink, and remember it for later.
1097 				if (forwards) {
1098 					index[v] = lowLinks[v] = nextIndex++;
1099 					set.push(v);
1100 				} else {
1101 					// If backtracking, update v's lowlink using its child w.
1102 					node w = outEdges->popFrontRet()->target();
1103 					Math::updateMin(lowLinks[v], lowLinks[w]);
1104 				}
1105 
1106 				// For all direct successors w of v:
1107 				while (!outEdges->empty() && !restartLoop) {
1108 					node w = outEdges->front()->target();
1109 
1110 					// If w is unvisited, continue the dfs with w.
1111 					if (index[w] == -1) {
1112 						stack.push(StackElem(w));
1113 						forwards = true;
1114 						restartLoop = true;
1115 					} else {
1116 						// Else update v's lowlink.
1117 						Math::updateMin(lowLinks[v], lowLinks[w]);
1118 						outEdges->popFront();
1119 					}
1120 				}
1121 
1122 				if (restartLoop) {
1123 					continue;
1124 				}
1125 
1126 				// The nodes collected so far form one component.
1127 				if (lowLinks[v] == index[v]) {
1128 					node w;
1129 					do {
1130 						w = set.popRet();
1131 						components[w] = result;
1132 						lowLinks[w] = nNodes;
1133 					} while (w != v);
1134 					result++;
1135 				}
1136 
1137 				// v has no more children to visit. Backtrack.
1138 				stack.pop();
1139 				forwards = false;
1140 				delete outEdges;
1141 			}
1142 		}
1143 	}
1144 
1145 	return result;
1146 }
1147 
1148 // makes the DiGraph bimodal such that all embeddings of the
1149 // graph are bimodal embeddings!
makeBimodal(Graph & G,List<edge> & newEdge)1150 void makeBimodal(Graph &G, List<edge> &newEdge)
1151 {
1152 	List<node> nodes;
1153 	G.allNodes(nodes);
1154 
1155 	ListIterator<node> it_n = nodes.begin();
1156 	while (it_n.valid()) {
1157 		node v = *it_n;
1158 		if (v->indeg() < 2 || v->outdeg() < 2) {
1159 			++it_n; continue;
1160 		}
1161 		List<adjEntry> newOrder;
1162 		for (adjEntry adj : v->adjEntries) {
1163 			if (adj->theEdge()->target() == v)
1164 				newOrder.pushFront(adj);
1165 			else
1166 				newOrder.pushBack(adj);
1167 		}
1168 		G.sort(v, newOrder);
1169 
1170 		ListIterator<adjEntry> it = newOrder.begin();
1171 		while ((*it)->theEdge()->target() == v)
1172 			++it;
1173 		node newNode = G.splitNode(newOrder.front(), *it);
1174 		for (adjEntry adj : newNode->adjEntries) {
1175 			if (adj->theEdge()->target() == newNode) {
1176 				newEdge.pushBack(adj->theEdge());
1177 				break;
1178 			}
1179 		}
1180 		++it_n;
1181 	}
1182 }
1183 
1184 // Forest and arborescence testing
1185 
isArborescenceForest(const Graph & G,List<node> & roots)1186 bool isArborescenceForest(const Graph& G, List<node> &roots)
1187 {
1188 	roots.clear();
1189 	if (G.empty()) {
1190 		return true;
1191 	}
1192 
1193 	if (G.numberOfNodes() <= G.numberOfEdges()) {
1194 		return false;
1195 	}
1196 
1197 	ArrayBuffer<node> stack;
1198 	int nodeCount = 0;
1199 
1200 	// Push every source node to roots and start a dfs from it.
1201 	for (node u : G.nodes) {
1202 		if (u->indeg() == 0) {
1203 			roots.pushBack(u);
1204 			stack.push(u);
1205 
1206 			while (!stack.empty()) {
1207 				// Get node v from the stack and increase the node counter.
1208 				node v = stack.popRet();
1209 				nodeCount++;
1210 
1211 				// Push all successors of v to the stack.
1212 				// If one of them has indegree > 1, return false.
1213 				for (adjEntry adj : v->adjEntries) {
1214 					if (adj->isSource()) {
1215 						node w = adj->twinNode();
1216 						if (w->indeg() > 1) {
1217 							return false;
1218 						}
1219 						stack.push(w);
1220 					}
1221 				}
1222 			}
1223 		}
1224 	}
1225 
1226 	// If there are still unvisited nodes, return false, else true.
1227 	return nodeCount == G.numberOfNodes();
1228 }
1229 
1230 
isArborescence(const Graph & G,node & root)1231 bool isArborescence (const Graph& G, node &root)
1232 {
1233 	List<node> roots;
1234 
1235 	if (isArborescenceForest(G,roots) && roots.size() == 1) {
1236 		root = roots.front(); return true;
1237 	}
1238 	return false;
1239 }
1240 
isRegular(const Graph & G)1241 bool isRegular(const Graph& G) {
1242 	if (G.numberOfEdges() == 0) {
1243 		return true;
1244 	}
1245 	return isRegular(G, G.firstNode()->degree());
1246 }
1247 
isRegular(const Graph & G,int d)1248 bool isRegular(const Graph& G, int d) {
1249 	for (auto n: G.nodes) {
1250 		if (n->degree() != d) {
1251 			return false;
1252 		}
1253 	}
1254 	return true;
1255 }
1256 
isBipartite(const Graph & G,NodeArray<bool> & color)1257 bool isBipartite(const Graph &G, NodeArray<bool> &color) {
1258 	ArrayBuffer<node> stack;
1259 	NodeArray<bool> visited(G, false);
1260 
1261 	// Start a depth-first search from every unvisited node.
1262 	for (node root : G.nodes) {
1263 		if (!visited[root]) {
1264 			stack.push(root);
1265 			color[root] = true;
1266 			visited[root] = true;
1267 
1268 			while (!stack.empty()) {
1269 				node v = stack.popRet();
1270 
1271 				// For all adjacent nodes w of v:
1272 				for (adjEntry adj : v->adjEntries) {
1273 					node w = adj->twinNode();
1274 
1275 					// If w is already visited/on the stack, check its color.
1276 					if (visited[w]) {
1277 						if (color[w] == color[v]) {
1278 							return false;
1279 						}
1280 					} else {
1281 						// Else color it and push it on the stack.
1282 						visited[w] = true;
1283 						color[w] = !color[v];
1284 						stack.push(w);
1285 					}
1286 				}
1287 			}
1288 		}
1289 	}
1290 
1291 	return true;
1292 }
1293 
nodeDistribution(const Graph & G,Array<int> & dist,std::function<int (node)> func)1294 void nodeDistribution(const Graph& G, Array<int> &dist, std::function<int(node)> func) {
1295 	int maxval = 0;
1296 	int minval = std::numeric_limits<int>::max();
1297 
1298 	if (G.empty()) {
1299 		dist.init();
1300 		return;
1301 	}
1302 
1303 	for (node v : G.nodes) {
1304 		Math::updateMax(maxval, func(v));
1305 		Math::updateMin(minval, func(v));
1306 	}
1307 
1308 	dist.init(minval, maxval, 0);
1309 	for (node v : G.nodes) {
1310 		++dist[func(v)];
1311 	}
1312 }
1313 
1314 }
1315