def is_cyclic(directed_graph): """ Function that checks whether a directed graph contains a cycle or not Args: directed_graph (DirectedGraph): The directed graph Returns: bool: True if the directed graph contains a cycle, otherwise False """ Logging.log("\nStarting cycle check") traversed_already = dict() in_cycle = {i:False for i in directed_graph.get_vertices().keys()} for label, vertex in directed_graph.get_vertices().items(): if traversed_already.get(label) is None: if is_cyclic_dfs(directed_graph, vertex, traversed_already, in_cycle): return True return False
def create_sccs_kosaraju_dfs(directed_graph, nontrivial): """ Function that creates a list of strongly connected components according to Kosaraju's algorithm (https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm) with a depth-first-search approach. Args: directed_graph (DirectedGraph): The directed graph for which the SCCS should be calculated nontrivial(bool): If True, only nontrivial sccs will be returned, otherwise all sccs Returns: list(set()) of SCCs: Each SCC is a set of vertices """ Logging.log("\nStarting") stack = [] sccs_trivial, visited = list(), dict() for vertex in directed_graph.get_vertices().keys(): if visited.get(vertex) is None: Logging.log("Vertex {0} not visited, go deep", vertex) kh.fill_order_dfd_sccs(directed_graph, vertex, visited, stack) else: Logging.log("Vertex {0} already visited, skipping", vertex) reversed_graph = get_reversed_graph(directed_graph) visited = dict() for i in reversed(stack): if visited.get(i) is None: sccs_trivial.append(set()) kh.visit_dfs_sccs(reversed_graph, i, visited, sccs_trivial[-1]) if nontrivial: return filter_nontrivial(sccs_trivial, directed_graph) else: return sccs_trivial
def fill_order_dfd_sccs(directed_graph, vertex, visited, stack): """ Function that covers the first part of the algorith by determining the order of vertices, traversing the graph with a depth first search, recursively Args: directed_graph (DirectedGraph): The directed graph vertex: The current vertex visited (dict): A dictionary that maintains whether vertices have been visisted stack (list): stack that will be processed, used to inverse the order """ visited[vertex] = True for head in directed_graph.get_vertices()[vertex].get_heads(): Logging.log("Vertex {0}, head {1} in fill order starting", vertex, head.get_label()) if visited.get(head.get_label()) is None: Logging.log( "Vertex {0}, head {1} not visited, go to fill order rec.", vertex, head.get_label()) Logging.inc_indent() fill_order_dfd_sccs(directed_graph, head.get_label(), visited, stack) Logging.dec_indent() Logging.log("Vertex {0}, head {1} returned from fill order", vertex, head.get_label()) Logging.log("Vertex {0}, head {1} in fill order finished", vertex, head.get_label()) else: Logging.log("Vertex {0}, head {1} already visited, skipping", vertex, head.get_label()) Logging.log("Vertex {0}, head {1} in fill order finished", vertex, head.get_label()) stack = stack.append(vertex)