'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