function is_cyclic
Detects whether a directed graph contains a cycle using depth-first search with path tracking.
/tf/active/vicechatdev/patches/util.py
1369 - 1384
moderate
Purpose
This function implements cycle detection in directed graphs using a recursive depth-first search algorithm. It maintains a path set to track the current traversal path and checks if any vertex is revisited during the same path, which indicates a cycle. The algorithm is useful for dependency resolution, detecting circular references, topological sorting validation, and ensuring acyclic properties in directed graph structures.
Source Code
def is_cyclic(graph):
"""
Return True if the directed graph g has a cycle. The directed graph
should be represented as a dictionary mapping of edges for each node.
"""
path = set()
def visit(vertex):
path.add(vertex)
for neighbour in graph.get(vertex, ()):
if neighbour in path or visit(neighbour):
return True
path.remove(vertex)
return False
return any(visit(v) for v in graph)
Parameters
| Name | Type | Default | Kind |
|---|---|---|---|
graph |
- | - | positional_or_keyword |
Parameter Details
graph: A dictionary representing a directed graph where keys are vertex identifiers and values are iterables (lists, tuples, sets) containing the neighbors/successors of that vertex. Empty iterables or missing keys indicate vertices with no outgoing edges. Example: {'A': ['B', 'C'], 'B': ['C'], 'C': []}
Return Value
Returns a boolean value: True if the directed graph contains at least one cycle (a path that leads back to a vertex already in the current traversal path), False if the graph is acyclic (contains no cycles).
Usage Example
# Example 1: Graph with a cycle
graph_with_cycle = {
'A': ['B'],
'B': ['C'],
'C': ['A'] # Creates cycle: A -> B -> C -> A
}
result = is_cyclic(graph_with_cycle)
print(result) # Output: True
# Example 2: Acyclic graph (DAG)
acyclic_graph = {
'A': ['B', 'C'],
'B': ['D'],
'C': ['D'],
'D': []
}
result = is_cyclic(acyclic_graph)
print(result) # Output: False
# Example 3: Self-loop
self_loop_graph = {
'A': ['A'] # Self-loop is a cycle
}
result = is_cyclic(self_loop_graph)
print(result) # Output: True
# Example 4: Disconnected graph
disconnected_graph = {
'A': ['B'],
'B': [],
'C': ['D'],
'D': ['C'] # Cycle in second component
}
result = is_cyclic(disconnected_graph)
print(result) # Output: True
Best Practices
- Ensure the graph parameter is a dictionary with vertex keys mapping to iterable collections of neighbors
- The function modifies the 'path' set during execution but restores it (backtracking), making it safe for reuse
- Works with any hashable vertex identifiers (strings, integers, tuples, etc.)
- For large graphs, consider the recursion depth limit; Python's default is typically 1000
- The algorithm visits each vertex and edge at most once, giving O(V + E) time complexity
- Missing vertices in the dictionary are treated as having no outgoing edges (handled by graph.get(vertex, ()))
- The function checks all connected components, not just vertices reachable from a single starting point
- For very deep graphs, you may need to increase recursion limit with sys.setrecursionlimit() or implement an iterative version
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
function sort_topologically 50.1% similar
-
function one_to_one 49.8% similar
-
function get_dbo_establishmentcycles_with_references_establishment_dbo_establishment 41.3% similar
-
function get_all_dbo_establishmentcycles 40.3% similar
-
function get_document_approvals 40.0% similar