Daniel S.
Daniel S.

Reputation: 6650

For a given node, how to find small cycles of which that node is a member?

I'm using python and graph-tool to do graph analysis. In a graph g, I want to find all cycles up to a specific length max_length of which a given node node is a member.

Related question:
How to iterate simple cycles in ascending cycle length order? is a broader question, which is more general and about a broader aspect. These questions act on different levels of abstraction and they are not duplicates of each other.

I've tried graph_tool.topology.all_circuits, but that runs far too long. It finds way too many cycles, e.g. for a graph with just 34 nodes, it finds 1462130 many cycles. In practice, I want to analyse a graph with more than 2 million nodes and there it would probably run for years. Here is an example to test this:

import graph_tool.collection
import graph_tool.topology

g = graph_tool.collection.data["karate"]

print("number of nodes in graph:", g.num_vertices())

print()
print(f"circ_idx\tcircuit")
circuit_iter = graph_tool.topology.all_circuits(g)
i = 0
for circuit in circuit_iter:
    i += 1
    if i % 152371 == 0:
        print(f"{i}\t{circuit}")

print("total number of circuits:", i)

Output:

number of nodes in graph: 34

circ_idx        circuit
152371  [ 0  3  1 13  2 28 31 25 24 27 33 29 23 32  8]
304742  [ 0  7  1 30 32 23 33 27 24 25 31 28  2  3 12]
457113  [ 0  8 30  1 19 33 18 32 29 23 25 24 31]
609484  [ 0  8 33 27 24 25 23 29 32  2  3]
761855  [ 0 13  1  7  3  2 32 31 25 23 33 19]
914226  [ 0 17  1  7  3  2 32 31 24 27 23 29 33 30  8]
1066597 [ 0 19 33 27 24 25 23 29 32 30  1  3]
1218968 [ 0 31 24 27 23 29 26 33 22 32  2  3 12]
1371339 [ 0 31 32 23 25 24 27 33 13  3  2  1 30  8]
total number of circuits: 1462130

Therefore, I think that the best approach is to use breadth first search (BFS), starting at node node, to find the cycles up to a specific length of which this node is a member, and stopping the BFS when the max_length is reached. I've tried that using graph_tool.search.bfs_iterator and graph_tool.search.bfs_search, but surprisingly, neither of them can be used to find cycles at all, as can be seen from the output of the following program:

import graph_tool.collection
import graph_tool.search

g = graph_tool.collection.data["karate"]
print("number of nodes in graph:", g.num_vertices())

print()
print("adjacencies")
for src in range(5):
    neighbors_list = g.get_all_neighbors(src)
    neighbors_list.sort()
    print("   ", src, neighbors_list)
print("    ...")

node = 0

print()
print("graph_tool.search.bfs_iterator")
bfs_iter = graph_tool.search.bfs_iterator(g, node)
for edge in bfs_iter:
    src = g.vertex_index[edge.source()]
    tar = g.vertex_index[edge.target()]
    found = "   ############################## cycle found!!!" if tar == node else "   no cycle found"
    print("   ", src, tar, found)

Output:

number of nodes in graph: 34

adjacencies
    0 [ 1  2  3  4  5  6  7  8 10 11 12 13 17 19 21 31]
    1 [ 0  2  3  7 13 17 19 21 30]
    2 [ 0  1  3  7  8  9 13 27 28 32]
    3 [ 0  1  2  7 12 13]
    4 [ 0  6 10]
    ...

graph_tool.search.bfs_iterator
    0 1    no cycle found
    0 2    no cycle found
    0 3    no cycle found
    0 4    no cycle found
    0 5    no cycle found
    0 6    no cycle found
    0 7    no cycle found
    0 8    no cycle found
    0 10    no cycle found
    0 11    no cycle found
    0 12    no cycle found
    0 13    no cycle found
    0 17    no cycle found
    0 19    no cycle found
    0 21    no cycle found
    0 31    no cycle found
    1 30    no cycle found
    2 9    no cycle found
    2 27    no cycle found
    2 28    no cycle found
    2 32    no cycle found
    5 16    no cycle found
    8 33    no cycle found
    31 24    no cycle found
    31 25    no cycle found
    27 23    no cycle found
    32 14    no cycle found
    32 15    no cycle found
    32 18    no cycle found
    32 20    no cycle found
    32 22    no cycle found
    32 29    no cycle found
    33 26    no cycle found

The graph_tool.search.bfs_search together with a BFSVisitor is another approach to BFS, but it has the same obstacle for detecting cycles, and it is thus unusable for my purpose. (Update: I doubt my own assessment here. See comment.)

Do I really have to implement BFS on my own in order to use a BFS for cycle detection? It's not tons of work, but I wonder if there is a better alternative. Moreover, implementing it in python will make it slow.

Upvotes: 0

Views: 118

Answers (0)

Related Questions