Skip to content

Instantly share code, notes, and snippets.

@hsanchez
Forked from joe-jordan/cycles.py
Created July 18, 2021 07:58
Show Gist options
  • Save hsanchez/dc12a638a356ff66b5f24a646d46d98d to your computer and use it in GitHub Desktop.
Save hsanchez/dc12a638a356ff66b5f24a646d46d98d to your computer and use it in GitHub Desktop.
Function to find all the cycles in a networkx graph. Health warning: this thing is an NP-complete depth-first search, work hard to make the graphs you put into it small.
def find_all_cycles(G, source=None, cycle_length_limit=None):
"""forked from networkx dfs_edges function. Assumes nodes are integers, or at least
types which work with min() and > ."""
if source is None:
# produce edges for all components
nodes=[i[0] for i in nx.connected_components(G)]
else:
# produce edges for components with source
nodes=[source]
# extra variables for cycle detection:
cycle_stack = []
output_cycles = set()
def get_hashable_cycle(cycle):
"""cycle as a tuple in a deterministic order."""
m = min(cycle)
mi = cycle.index(m)
mi_plus_1 = mi + 1 if mi < len(cycle) - 1 else 0
if cycle[mi-1] > cycle[mi_plus_1]:
result = cycle[mi:] + cycle[:mi]
else:
result = list(reversed(cycle[:mi_plus_1])) + list(reversed(cycle[mi_plus_1:]))
return tuple(result)
for start in nodes:
if start in cycle_stack:
continue
cycle_stack.append(start)
stack = [(start,iter(G[start]))]
while stack:
parent,children = stack[-1]
try:
child = next(children)
if child not in cycle_stack:
cycle_stack.append(child)
stack.append((child,iter(G[child])))
else:
i = cycle_stack.index(child)
if i < len(cycle_stack) - 2:
output_cycles.add(get_hashable_cycle(cycle_stack[i:]))
except StopIteration:
stack.pop()
cycle_stack.pop()
return [list(i) for i in output_cycles]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment