Search code examples
pythongraphgraph-tool

Get all possible graphs with a given number of nodes and edges (with graph-tools)


I am pretty new to graph and my knowledge is near to 0. But I need to build a model in order to get all possible graph with a given number of edges, given number of nodes and the maximum degree between each node.

So for example i want to get all graphs possibility that have 8 nodes and exactly 3 connections (edges) between each node.

I also would like to get all the possibilities as a dictionary, like so :

{ 1 : [2,3,4],
  2 : [5,3,1],
  3 : [6,2,7]
... and so on

Of course an edge cannot be connected to itself.

So far i tried to use the graph-tools library (here)

and what i tried is :

from graph_tool.all import *

def degree () :
    return 3,3
g = random_graph(8, degree)
a = g.get_edges([g.edge_index])
print(a)

Which output me :

[[ 0  7  0]
 [ 0  5  2]
 [ 0  2  1]
 [ 1  7 12]
 [ 1  5 14]
 [ 1  6 13]
 [ 2  3  9]
 [ 2  4 10]
 [ 2  1 11]
 [ 3  6 22]
 [ 3  0 23]
 [ 3  1 21]
 [ 4  3  3]
 [ 4  1  5]
 [ 4  0  4]
 [ 5  2 20]
 [ 5  0 19]
 [ 5  4 18]
 [ 6  7 15]
 [ 6  5 16]
 [ 6  4 17]
 [ 7  6  8]
 [ 7  3  7]
 [ 7  2  6]]

Can someone explain me what am i doing wrong here ? (for example why the first list is 0,7,0 (what does it means...again i am totally new to this kind of stuff))

Why is there number greater than 7 if i defined only 8 nodes ?

How can i get all the possibilities (all graphs of 8 nodes and exactly 3 connections between each nodes) ?


Solution

  • I am not sure what do you try to achieve, but I wrote a code to solve a similar problem and generate data structure from random distinct graphs generated with graph tools library.

    It might helps you to get what you need.

    If you got any question, let me know.

    from graph_tool.all import *
    import json
    
    def isDifferentList(list1, list2):
        return list1 != list2
    
    
    def isDifferentGraph(graph1, graph2):
        for k in graph1.keys():
            if isDifferentList(graph1[k], graph2[k]):
                # if all lists of connection exists, return true and stop all iterations,
                # this mean that the graph exists, so need to generate a new one
                return True
        #the graph does not exist, we can continue with the current one
        return False
    
    
    def graphExists(graph, all):
        for generated in all:
            if not isDifferentGraph(graph, generated):
                return True
        return False
    
    
    def generate_output_data(gr):
        gGraph = {}
        for vertex in gr.get_edges():
            vertex0 = int(vertex[0]) + 1
            vertex1 = int(vertex[1]) + 1
            if int(vertex0) not in gGraph:
                gGraph[vertex0] = []
            if vertex1 not in gGraph:
                gGraph[vertex1] = []
            gGraph[vertex0].append(vertex1)
            gGraph[vertex1].append(vertex0)
        return gGraph
    
    
    def getRandomGraph():
        return generate_output_data(random_graph(VERTICES, lambda: DEGREE, directed=False))
    
    
    def defineDegreeAndvertexs(vertexs, in_degree):
        global VERTICES, DEGREE
        DEGREE = in_degree
        VERTICES = vertexs
    
    
    def generateNgraph(in_vertices, in_degree, n_graphs):
        #first store inputs in globals variable
        defineDegreeAndvertexs(in_vertices, in_degree)
    
        #generate empty list of generated uniques graphs
        all_graphs = []
        for i in range(0, n_graphs):
    
            #generate a new random graph and get it as a desired output data struct
            g = getRandomGraph()
    
            # check if this graph already exists and generate a new one as long as it already been generated
            while graphExists(g, all_graphs):
                g = getRandomGraph()
    
            #Write the new graph in a text file
            with open("graphs.txt", 'a+') as f:
                f.write(json.dumps(g))
                f.write("\n")
    
            #append the new graph in the all graph list - this list will be the input for the graphExists function
            all_graphs.append(g)
    
    
    if __name__ == '__main__':
        generateNgraph(8, 3, 1500)
    
    
    

    Follow the main function here and its comments to understand the whole flow.

    Output :

    {"1": [2, 7, 5], "2": [1, 7, 5], "7": [1, 2, 6], "5": [1, 3, 2], "4": [6, 3, 8], "6": [4, 7, 8], "3": [4, 5, 8], "8": [6, 3, 4]}
    {"1": [8, 7, 2], "8": [1, 2, 6], "7": [1, 4, 5], "2": [1, 6, 8], "6": [2, 3, 8], "4": [7, 3, 5], "3": [4, 5, 6], "5": [4, 3, 7]}
    {"1": [8, 7, 5], "8": [1, 3, 2], "7": [1, 5, 6], "5": [1, 4, 7], "2": [3, 4, 8], "3": [2, 6, 8], "4": [6, 2, 5], "6": [4, 3, 7]}
    

    Where the key of each dictionary is a named vertex and the value is a list that represents the connected vertices.

    This is not a real optimized code since its complexity grows with the graphs generations. It will check each graph generated for each iteration so O(n) for the complexity.

    Now for you first question : how many graphs can we output with given n edges and given degree, first it might be no solution if you want all edges strictly connected. Second, it is a very complex mathematics question in my opinion.

    This is what i've found so far but fo implementing this in code I let others specialists to answer this (cause I have no clue sorry).

    https://math.stackexchange.com/questions/154941/how-to-calculate-the-number-of-possible-connected-simple-graphs-with-n-labelle