0

I would like to generate a random dictionary starting from an array with 5 elements. That dictionary would represent a planar graph. How can i generate a random dictionary that is a planar graph whose values and keys are the 5 elements of the array? This is what I tried:

q = [0, 1, 2, 3, 4]
d = {i: sample([j for j in q if i != j], randrange(1, len(q) - 1))
     for i in q}

Here is an example of the graph it generates:

{0: [1], 1: [4, 3], 2: [4], 3: [4], 4: [0, 2]}

As you can see, the problem is that it is not creating a proper adjacency matrix (3 is connected with 1 but 1 is not in its adjancey matrix) Some of you suggested me an already asked question, but the answer to that question is pretty complex as it generates a very big planar graph, the thing I’m trying to do here is a simple code that generate a small planar graph with 5 vertices. Keep in mind that the planarity of the graph can always be checked with checkplanarity from networkx, more on that here, the issue I need to solve is the adjacency of the matrix.

the reason I'm doing this is to then color the generated graph with four colors using the following function named coloring, and the matrix problem prevents me from coloring it proprely so that same colors never touch. To feed the function coloring with the created graph I do the following:

def coloring(adj, V):
    result = [-1] * V
    result[0] = 0
    available = [False] * V
    # add values to adj matrices
    for y in range(0, V):
        for x in adj[y]:
            if y not in adj[x]:
                adj[x].append(y)

    for u in range(1, V):
        for i in adj[u]:
            if (result[i] != -1):
                available[result[i]] = True
        cr = 0
        while cr < V:
            if (available[cr] == False):
                break

            cr += 1

        result[u] = cr

        for i in adj[u]:
            if (result[i] != -1):
                available[result[i]] = False

    for u in range(V):
        print("Vertex", u, " --->  Color", result[u])

To feed the function coloring with the created graph d I do the following:

coloring([node for node in d.values()], 5)
Emilio
  • 102
  • 11
  • 2
    `and that has as values the elements of the array?` ... what does that mean? – chitown88 Jan 26 '22 at 12:52
  • Might help if you explain at a high level what a planar graph is (as represented by a list of values) – chitown88 Jan 26 '22 at 12:53
  • @chitown88 a planar graph is a graph that can be drawn in to the 2 plane with out any lines crossing each other. For example of you draw a rectangle an the corner points are the knots in the graph that would be a planar graph – gerda die gandalfziege Jan 26 '22 at 12:57
  • Does this answer your question? [Generate a large random planar graph](https://stackoverflow.com/questions/3232048/generate-a-large-random-planar-graph) – Tom Aarsen Jan 26 '22 at 12:59
  • See also https://stackoverflow.com/questions/58050200/how-to-draw-a-planar-graph-with-networkx – AKX Jan 26 '22 at 12:59
  • @TomAarsen Unfortunately it doesn’t answer my question. I have edited the question explaining why – Emilio Jan 26 '22 at 13:20
  • How can you ensure that it is a planar graph? Generating some random graph in your structure seems to be the easier part. Do you need to solve only the adjacency of the matrix? – DanielTuzes Jan 26 '22 at 13:35
  • @DanielTuzes it can be done with the `checkplanarity` function provided by `networkx`I added it to the question. And yes, what I want to fix is the adjacency of the matrix. Thanks – Emilio Jan 26 '22 at 13:54

2 Answers2

1

Let's do this with numpy.

  1. Let's create a random matrix with random number between 0 to 9 of size nxn = 5x5
  2. Next, let's sum the matrix with its transpose to ensure that it is symmetrix
  3. Fix the diagonal with np.fill_diagonal to remove self loops
  4. Define a condition connectivity, the larger it is, lower the number of connections in your random graph.
  5. Finally convert the matrix into a dictionary
  6. Plot.
import numpy as np
import networkx as nx

def random_graph(vertices, connectivity):
    #Creates random symmetric graph
    arr = np.random.randint(0,10,(vertices,vertices))
    sym = (arr+arr.T)
    
    #removing self loops with fixing diagonal
    np.fill_diagonal(sym,0)
    
    #connectivity of graph -> 0 for highest connections, 9 for least connections
    mat = (sym>connectivity).astype(int)
    
    #convert to dictionary
    G = {k:[i for i,j in enumerate(v) if j==1] for k,v in enumerate(mat)}
    return G

Generating graph with high connections (connectivity = 0) -

G = random_graph(5, 0)
g = nx.Graph(G)
print(G)
nx.draw(g)
{0: [1, 2, 3, 4],
 1: [0, 2, 3, 4],
 2: [0, 1, 3, 4],
 3: [0, 1, 2, 4],
 4: [0, 1, 2, 3]}

enter image description here

Generating graph with lower connections (connectivity = 8) -

G = random_graph(5, 8)
g = nx.Graph(G)
print(G)
nx.draw(g)
{0: [2, 3], 
 1: [2, 3, 4], 
 2: [0, 1, 4], 
 3: [0, 1], 
 4: [1, 2]}

enter image description here

Akshay Sehgal
  • 18,741
  • 3
  • 21
  • 51
  • thank you, but I get the following error in the `random_graph` function that you have provided me with: `Traceback (most recent call last): File "c:\Users\besan\OneDrive\Desktop\LAM da correggere\test.py", line 56, in G = random_graph(5, 0) File "c:\Users\besan\OneDrive\Desktop\LAM da correggere\test.py", line 46, in random_graph arr = np.random.randint(0,10,(n,n)) NameError: name 'n' is not defined` – Emilio Jan 26 '22 at 14:52
  • furthermore, how can I avoid that nodes are connected to themselfes? – Emilio Jan 26 '22 at 14:53
  • i have edited the question adding more context, helping you help me – Emilio Jan 26 '22 at 15:26
  • Updated my answer, the `n` was a bug on my part, fixed it! Also, added an additional part to remove self-loops. Do check the answer and if it worked for you then do mark & vote the answer. let me know if you need any specific clarifications on the solution above. – Akshay Sehgal Jan 27 '22 at 09:47
  • thank you, it works perfectly now, I was going crazy on this script. One more thing, I was thinking of randomizing the connectivity by generating a random number between 0 and 10. Do you have a better idea on how to add a simple element of randomness to the graph? – Emilio Jan 27 '22 at 12:56
  • `One more thing, I was thinking of randomizing the connectivity by generating a random number between 0 and 10` could you elaborate on this with an example? maybe i could spend some time as adding that as an additional part to the above solution :) – Akshay Sehgal Jan 27 '22 at 13:26
  • Do make sure to mark and vote the above answer if it solved your current problem though, motivates me to solve any future problems that you post! thanks! – Akshay Sehgal Jan 27 '22 at 13:27
  • marked and also upvoted, if yo have any ideas on some randomization for the graph let me know :) – Emilio Jan 27 '22 at 13:28
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/241457/discussion-between-akshay-sehgal-and-emilio). – Akshay Sehgal Jan 27 '22 at 13:29
  • if I try to do create a graph with more than 5 vertices, I get the following error when coloring it with the `coloring` function: `Traceback (most recent call last): File "c:\Users\besan\OneDrive\Desktop\LAM da stampare\stacktest.py", line 79, in coloring([node for node in G.values()], 5) File "c:\Users\besan\OneDrive\Desktop\LAM da stampare\stacktest.py", line 22, in coloring if (result[i] != -1): IndexError: list index out of range` – Emilio Feb 09 '22 at 16:58
1

With a slight modification to your code, you can symmetrize your graph:

import random
random.seed(0)

q = [0, 1, 2, 3, 4]
d = {i: set(random.sample([j for j in q if i != j], random.randrange(1, len(q) - 1)))
     for i in q}

Now symmetrize:

for node in d:
    for link_target in d[node]:
        d[link_target].add(node)

This way nodes are not connected to themselves, just as in your code. You still have to verify whether the graph is planar.

Set the number of edges

If you wish to fix the number of edges to k, here's what you can do:

  1. generate a triangular matrix with zeros in the diagonal, using zeros (false) and ones (true) to represent connectivity between edges. You can do it by random shuffling k ones and N*(N-1)/2 zeros and distributing them onto non-diagonal places of the triangular matrix.
  2. add the transpose of the matrix to itself
  3. convert the matrix to the dictionary format you prefer.

Note: you still have to confirm whether the graph is planar.

DanielTuzes
  • 2,494
  • 24
  • 40
  • i have edited the question adding more context, helping you help me – Emilio Jan 26 '22 at 15:26
  • Without ensuring the symmetry, by omitting the for loop, the code above produces `{0: {1, 4}, 1: {2, 4}, 2: {1, 4}, 3: {0, 1, 2}, 4: {0, 1}}`. Using the for loop to ensure symmetry, the result is `{0: {1, 3, 4}, 1: {0, 2, 3, 4}, 2: {1, 3, 4}, 3: {0, 1, 2}, 4: {0, 1, 2}}` Does it solve your problem? – DanielTuzes Jan 26 '22 at 15:53
  • unfortunately it doesn't. In the question I published my entire coloring program so that maybe you can understand what's wrong. Again, my final goal is to color the graph with four colors without having same colors adjacent to oneanother – Emilio Jan 26 '22 at 16:54
  • How do you feed `coloring` with `u` and `d`? – DanielTuzes Jan 26 '22 at 21:12
  • I have just updated the question explaining more on that – Emilio Jan 26 '22 at 22:01