Source code for networkx.generators.nonisomorphic_trees
"""Implementation of the Wright, Richmond, Odlyzko and McKay (WROM)algorithm for the enumeration of all non-isomorphic free trees of agiven order. Rooted trees are represented by level sequences, i.e.,lists in which the i-th element specifies the distance of vertex i tothe root."""__all__=["nonisomorphic_trees","number_of_nonisomorphic_trees"]importnetworkxasnx
[docs]defnonisomorphic_trees(order,create="graph"):"""Returns a list of nonisomporphic trees Parameters ---------- order : int order of the desired tree(s) create : graph or matrix (default="Graph) If graph is selected a list of trees will be returned, if matrix is selected a list of adjancency matrix will be returned Returns ------- G : List of NetworkX Graphs M : List of Adjacency matrices References ---------- """iforder<2:raiseValueError# start at the path graph rooted at its centerlayout=list(range(order//2+1))+list(range(1,(order+1)//2))whilelayoutisnotNone:layout=_next_tree(layout)iflayoutisnotNone:ifcreate=="graph":yield_layout_to_graph(layout)elifcreate=="matrix":yield_layout_to_matrix(layout)layout=_next_rooted_tree(layout)
[docs]defnumber_of_nonisomorphic_trees(order):"""Returns the number of nonisomorphic trees Parameters ---------- order : int order of the desired tree(s) Returns ------- length : Number of nonisomorphic graphs for the given order References ---------- """returnsum(1for_innonisomorphic_trees(order))
def_next_rooted_tree(predecessor,p=None):"""One iteration of the Beyer-Hedetniemi algorithm."""ifpisNone:p=len(predecessor)-1whilepredecessor[p]==1:p-=1ifp==0:returnNoneq=p-1whilepredecessor[q]!=predecessor[p]-1:q-=1result=list(predecessor)foriinrange(p,len(result)):result[i]=result[i-p+q]returnresultdef_next_tree(candidate):"""One iteration of the Wright, Richmond, Odlyzko and McKay algorithm."""# valid representation of a free tree if:# there are at least two vertices at layer 1# (this is always the case because we start at the path graph)left,rest=_split_tree(candidate)# and the left subtree of the root# is less high than the tree with the left subtree removedleft_height=max(left)rest_height=max(rest)valid=rest_height>=left_heightifvalidandrest_height==left_height:# and, if left and rest are of the same height,# if left does not encompass more verticesiflen(left)>len(rest):valid=False# and, if they have the same number or vertices,# if left does not come after rest lexicographicallyeliflen(left)==len(rest)andleft>rest:valid=Falseifvalid:returncandidateelse:# jump to the next valid free treep=len(left)new_candidate=_next_rooted_tree(candidate,p)ifcandidate[p]>2:new_left,new_rest=_split_tree(new_candidate)new_left_height=max(new_left)suffix=range(1,new_left_height+2)new_candidate[-len(suffix):]=suffixreturnnew_candidatedef_split_tree(layout):"""Returns a tuple of two layouts, one containing the left subtree of the root vertex, and one containing the original tree with the left subtree removed."""one_found=Falsem=Noneforiinrange(len(layout)):iflayout[i]==1:ifone_found:m=ibreakelse:one_found=TrueifmisNone:m=len(layout)left=[layout[i]-1foriinrange(1,m)]rest=[0]+[layout[i]foriinrange(m,len(layout))]return(left,rest)def_layout_to_matrix(layout):"""Create the adjacency matrix for the tree specified by the given layout (level sequence)."""result=[[0]*len(layout)foriinrange(len(layout))]stack=[]foriinrange(len(layout)):i_level=layout[i]ifstack:j=stack[-1]j_level=layout[j]whilej_level>=i_level:stack.pop()j=stack[-1]j_level=layout[j]result[i][j]=result[j][i]=1stack.append(i)returnresultdef_layout_to_graph(layout):"""Create a NetworkX Graph for the tree specified by the given layout(level sequence)"""result=[[0]*len(layout)foriinrange(len(layout))]G=nx.Graph()stack=[]foriinrange(len(layout)):i_level=layout[i]ifstack:j=stack[-1]j_level=layout[j]whilej_level>=i_level:stack.pop()j=stack[-1]j_level=layout[j]G.add_edge(i,j)stack.append(i)returnG