'Generate digraph with given undirected girth
I need a python function to generate the adjacency matrix of a digraph given it's size n, it's undirected girth (minimal size of a undirected cycle) girth and a minimal out-degree delta. I already have a similar function that generate a matrix for directed girth (summary of how it works after the code):
def generation(n, girth = 3, delta = 1):
'''
generate a random adjacency matrix.
girth: minimum size of a DIRECTED cycle; default 3. Note that the generate adjacency matrix has girth at least girth, but not necessarly equal.
delta: minimum out-degree, default 1. delta > 0 implies sink-free graphs.
'''
# method: start with a full graph; find all the edges that cause a problem (double edges or induce a cycle too small) and pick one randomly to remove.
# TODO: this generation is not very good as it only generate graph that are maximal in terms of edges. A directed consequence is that passing girht = 3 yields 100% of the time a tournament.
# An improvement would be to start with a more random graph.
A = 1 - np.eye(n)
correct = False
def find_bad_edges(A, girth):
# ''' return list of edges (format (i,j)) such that they belong to a cycle of small enough girth.'''
n = len(A)
B = (np.eye(n) + A)
B = np.linalg.matrix_power(B, girth -2 )
bad_edges = []
for i in range(n):
for j in range(n):
if A[i,j] == 1 and B[j,i]>=1:
bad_edges.append((i,j))
elif A[i,j] == 1 and A[j,i] == 1:
bad_edges.append((i,j))
return bad_edges
def can_remove(A, edge, delta):
# decide if we can remove edge from A without affecting the delta property.
i,j = edge
if sum(A[i]) <= delta:
return False
return True
while correct == False:
potential_bad_edges = find_bad_edges(A, girth)
BE = []
for be in potential_bad_edges:
if can_remove(A, be, delta):
BE.append(be)
if len(BE) != 0:
u = np.random.randint(len(BE))
i,j = BE[u][0], BE[u][1]
A[i,j] = 0
else:
#it may be possible we arrive here with a double edge but with impossibility to remove it without breaking the delta property.
#in that case it is necessary to detect it and restart the process.
if len(potential_bad_edges) == 0:
correct = True
else: #reset time !
A = 1 - np.eye(n)
return A
Simply put, I start with a complete graph (i,j) is an arc for every pair. Until the matrix is declared valid, I compute every "bad" edge by computing if they belong to a cycle of girth that is too small and store it in potential_bad_edge list. Then, for every edge, i check if it is possible to remove it without violating the out-degree property. If I can, I put it into BE list. Then, I pick randomly an edge from BE and start over again until potential_bad_edge is empty.
This function works well for what I need. I try to adapt it for my new problem (undirected girth) but somehow I can't make it work: either I loop infinitly, either it returns me a matrix containing an undirected cycle that is too small.
I also tried a similar approach in the spirit: generate a undirected graph with desired girth, and try to orient the edges afterwards; it always loops infinitly.
Do you have any idea of how to adapt the generation() function I gave to answer my problem? Or any totally different suggestion?
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
