ó ŸÃÒYc@ swdZddlmZddlZddlmZddlmZyddlmZWn!ek ryddlm ZnXddl Z ddl m Z ddl Z ddlZdd lmZd d d d dddgZejZd„Zeddd„Zddd„Zddd„Zded„Zdd„Zdd„Zdd„Zddd„Z de!fd„ƒYZ"dS(sJGenerate graphs with a given degree sequence or expected degree sequence. iÿÿÿÿ(tdivisionN(tchain(t combinations(t zip_longest(t izip_longest(t itemgetter(trandom_weighted_sampletconfiguration_modeltdirected_configuration_modeltexpected_degree_graphthavel_hakimi_graphtdirected_havel_hakimi_graphtdegree_sequence_treetrandom_degree_sequence_graphcC s ttd„t|ƒDƒƒƒS(sŠReturns a list of degree-repeated node numbers. ``degree_sequence`` is a list of nonnegative integers representing the degrees of nodes in a graph. This function returns a list of node numbers with multiplicities according to the given degree sequence. For example, if the first element of ``degree_sequence`` is ``3``, then the first node number, ``0``, will appear at the head of the returned list three times. The node numbers are assumed to be the numbers zero through ``len(degree_sequence) - 1``. Examples -------- >>> degree_sequence = [1, 2, 3] >>> _to_stublist(degree_sequence) [0, 1, 1, 2, 2, 2] If a zero appears in the sequence, that means the node exists but has degree zero, so that number will be skipped in the returned list:: >>> degree_sequence = [2, 0, 1] >>> _to_stublist(degree_sequence) [0, 0, 2] cs s"|]\}}|g|VqdS(N((t.0tntd((st/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/generators/degree_seq.pys Js(tlisttchainit enumerate(tdegree_sequence((st/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/generators/degree_seq.pyt _to_stublist-scC s |dk rtj|ƒnt|ƒ}tj|d|ƒ}|dkrM|S|r¯t||ddƒ}t|Œ\}} t|ƒ} t| ƒ} tj | ƒtj | ƒnDt|ƒ} t| ƒ}|d} tj | ƒ| | | | } } |j t| | ƒƒ|S(s/Helper function for generating either undirected or directed configuration model graphs. ``deg_sequence`` is a list of nonnegative integers representing the degree of the node whose label is the index of the list element. ``create_using`` is a NetworkX graph instance. For more information on this keyword argument, see :func:`~networkx.empty_graph`. ``directed`` and ``in_deg_sequence`` are required if you want the returned graph to be generated using the directed configuration model algorithm. If ``directed`` is ``False``, then ``deg_sequence`` is interpreted as the degree sequence of an undirected graph and ``in_deg_sequence`` is ignored. Otherwise, if ``directed`` is ``True``, then ``deg_sequence`` is interpreted as the out-degree sequence and ``in_deg_sequence`` as the in-degree sequence of a directed graph. .. note:: ``deg_sequence`` and ``in_deg_sequence`` need not be the same length. ``seed`` is the seed for the random number generator. This function returns a graph, directed if and only if ``directed`` is ``True``, generated according to the configuration model algorithm. For more information on the algorithm, see the :func:`configuration_model` or :func:`directed_configuration_model` functions. t create_usingit fillvalueiN( tNonetrandomtseedtlentnxt empty_graphRtzipRtshuffletadd_edges_from(t deg_sequenceRtdirectedtin_deg_sequenceRRtGtpairstout_degtin_degt out_stublistt in_stublisttstublistthalf((st/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/generators/degree_seq.pyt_configuration_modelMs("          cC s€t|ƒddkr.d}tj|ƒ‚n|dkrItjƒ}n|jƒrgtjdƒ‚nt||d|ƒ}|S(s Return a random graph with the given degree sequence. The configuration model generates a random pseudograph (graph with parallel edges and self loops) by randomly assigning edges to match the given degree sequence. Parameters ---------- deg_sequence : list of nonnegative integers Each list entry corresponds to the degree of a node. create_using : graph, optional (default MultiGraph) Return graph of this type. The instance will be cleared. seed : hashable object, optional Seed for random number generator. Returns ------- G : MultiGraph A graph with the specified degree sequence. Nodes are labeled starting at 0 with an index corresponding to the position in deg_sequence. Raises ------ NetworkXError If the degree sequence does not have an even sum. See Also -------- is_graphical Notes ----- As described by Newman [1]_. A non-graphical degree sequence (not realizable by some simple graph) is allowed since this function returns graphs with self loops and parallel edges. An exception is raised if the degree sequence does not have an even sum. This configuration model construction process can lead to duplicate edges and loops. You can remove the self-loops and parallel edges (see below) which will likely result in a graph that doesn't have the exact degree sequence specified. The density of self-loops and parallel edges tends to decrease as the number of nodes increases. However, typically the number of self-loops will approach a Poisson distribution with a nonzero mean, and similarly for the number of parallel edges. Consider a node with *k* stubs. The probability of being joined to another stub of the same node is basically (*k* - *1*) / *N*, where *k* is the degree and *N* is the number of nodes. So the probability of a self-loop scales like *c* / *N* for some constant *c*. As *N* grows, this means we expect *c* self-loops. Similarly for parallel edges. References ---------- .. [1] M.E.J. Newman, "The structure and function of complex networks", SIAM REVIEW 45-2, pp 167-256, 2003. Examples -------- You can create a degree sequence following a particular distribution by using the one of the distribution functions in :mod:`~networkx.utils.random_sequence` (or one of your own). For example, to create an undirected multigraph on one hundred nodes with degree sequence chosen from the power law distribution: >>> sequence = nx.random_powerlaw_tree_sequence(100, tries=5000) >>> G = nx.configuration_model(sequence) >>> len(G) 100 >>> actual_degrees = [d for v, d in G.degree()] >>> actual_degrees == sequence True The returned graph is a multigraph, which may have parallel edges. To remove any parallel edges from the returned graph: >>> G = nx.Graph(G) Similarly, to remove self-loops: >>> G.remove_edges_from(nx.selfloop_edges(G)) iis=Invalid degree sequence: sum of degrees must be even, not odds#not implemented for directed graphsRN(tsumRt NetworkXErrorRt MultiGrapht is_directedtNetworkXNotImplementedR,(R!RRtmsgR$((st/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/generators/degree_seq.pyR”sW  c C svt|ƒt|ƒkr0d}tj|ƒ‚n|dkrKtjƒ}nt||dtd|d|ƒ}d}|S(sž Return a directed_random graph with the given degree sequences. The configuration model generates a random directed pseudograph (graph with parallel edges and self loops) by randomly assigning edges to match the given degree sequences. Parameters ---------- in_degree_sequence : list of nonnegative integers Each list entry corresponds to the in-degree of a node. out_degree_sequence : list of nonnegative integers Each list entry corresponds to the out-degree of a node. create_using : graph, optional (default MultiDiGraph) Return graph of this type. The instance will be cleared. seed : hashable object, optional Seed for random number generator. Returns ------- G : MultiDiGraph A graph with the specified degree sequences. Nodes are labeled starting at 0 with an index corresponding to the position in deg_sequence. Raises ------ NetworkXError If the degree sequences do not have the same sum. See Also -------- configuration_model Notes ----- Algorithm as described by Newman [1]_. A non-graphical degree sequence (not realizable by some simple graph) is allowed since this function returns graphs with self loops and parallel edges. An exception is raised if the degree sequences does not have the same sum. This configuration model construction process can lead to duplicate edges and loops. You can remove the self-loops and parallel edges (see below) which will likely result in a graph that doesn't have the exact degree sequence specified. This "finite-size effect" decreases as the size of the graph increases. References ---------- .. [1] Newman, M. E. J. and Strogatz, S. H. and Watts, D. J. Random graphs with arbitrary degree distributions and their applications Phys. Rev. E, 64, 026118 (2001) Examples -------- One can modify the in- and out-degree sequences from an existing directed graph in order to create a new directed graph. For example, here we modify the directed path graph: >>> D = nx.DiGraph([(0, 1), (1, 2), (2, 3)]) >>> din = list(d for n, d in D.in_degree()) >>> dout = list(d for n, d in D.out_degree()) >>> din.append(1) >>> dout[0] = 2 >>> # We now expect an edge from node 0 to a new node, node 3. ... D = nx.directed_configuration_model(din, dout) The returned graph is a directed multigraph, which may have parallel edges. To remove any parallel edges from the returned graph: >>> D = nx.DiGraph(D) Similarly, to remove self-loops: >>> D.remove_edges_from(nx.selfloop_edges(D)) s8Invalid degree sequences: sequences must have equal sumsR"R#Rs.directed configuration_model {} nodes {} edgesN(R-RR.Rt MultiDiGraphR,tTrue(tin_degree_sequencetout_degree_sequenceRRR2R$tname((st/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/generators/degree_seq.pyRùsQ cC sþt|ƒ}tj|ƒ}|dks9t|ƒdkr=|S|dk rYtj|ƒndt|ƒ}tt |ƒdt dƒdt ƒ}d„t |ƒDƒ}g|D]\}} | ^qª} |} |sÛ| d8} nxt | ƒD]}|} |s| d7} n| ||} t | | | dƒ} xÇ| |krõ| dkrõ| dkr‹tjƒ}| ttjtj|d| ƒƒƒ7} n| |kr/t | | | dƒ}tjƒ|| krß|j|||| ƒn| d7} |} q/q/WqèW|S(saReturn a random graph with given expected degrees. Given a sequence of expected degrees $W=(w_0,w_1,\ldots,w_{n-1})$ of length $n$ this algorithm assigns an edge between node $u$ and node $v$ with probability .. math:: p_{uv} = \frac{w_u w_v}{\sum_k w_k} . Parameters ---------- w : list The list of expected degrees. selfloops: bool (default=True) Set to False to remove the possibility of self-loop edges. seed : hashable object, optional The seed for the random number generator. Returns ------- Graph Examples -------- >>> z=[10 for i in range(100)] >>> G=nx.expected_degree_graph(z) Notes ----- The nodes have integer labels corresponding to index of expected degrees input sequence. The complexity of this algorithm is $\mathcal{O}(n+m)$ where $n$ is the number of nodes and $m$ is the expected number of edges. The model in [1]_ includes the possibility of self-loop edges. Set selfloops=False to produce a graph without self loops. For finite graphs this model doesn't produce exactly the given expected degree sequence. Instead the expected degrees are as follows. For the case without self loops (selfloops=False), .. math:: E[deg(u)] = \sum_{v \ne u} p_{uv} = w_u \left( 1 - \frac{w_u}{\sum_k w_k} \right) . NetworkX uses the standard convention that a self-loop edge counts 2 in the degree of a node, so with self loops (selfloops=True), .. math:: E[deg(u)] = \sum_{v \ne u} p_{uv} + 2 p_{uu} = w_u \left( 1 + \frac{w_u}{\sum_k w_k} \right) . References ---------- .. [1] Fan Chung and L. Lu, Connected components in random graphs with given expected degree sequences, Ann. Combinatorics, 6, pp. 125-145, 2002. .. [2] Joel Miller and Aric Hagberg, Efficient generation of networks with given expected degrees, in Algorithms and Models for the Web-Graph (WAW 2011), Alan Frieze, Paul Horn, and PaweÅ‚ PraÅ‚at (Eds), LNCS 6732, pp. 115-126, 2011. iitkeytreversecS s%i|]\}\}}||“qS(((Rtctutv((st/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/generators/degree_seq.pys ­s N(RRRtmaxRRRR-tsortedRRR4trangetmintinttmathtfloortlogtadd_edge(twRt selfloopsRR$trhotordertmappingR;R<tseqtlasttfactortptrtq((st/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/generators/degree_seq.pyR Xs<G  $    ,  cC sktj|ƒs!tjdƒ‚n|dk rK|jƒrKtjdƒ‚nt|ƒ}tj||ƒ}gt|ƒD] }g^qv}d\}}}xS|D]K} | dkrž|| j|ƒt || ƒ|| |d}}}qžqžW|dkrý|Sdg|d} xV|dkrfx$t||ƒdkrC|d8}q W||dkrftjdƒ‚n||j ƒ} |d8}d} |} x’t|ƒD]„}x$t|| ƒdkrÅ| d8} q¢W|| j ƒ}|j | |ƒ|d8}| dkr™| d|f| | <| d7} q™q™Wx?t| ƒD]1}| |\}}||j|ƒ|d7}q.WqW|S( sŠReturn a simple graph with given degree sequence constructed using the Havel-Hakimi algorithm. Parameters ---------- deg_sequence: list of integers Each integer corresponds to the degree of a node (need not be sorted). create_using : graph, optional (default Graph) Return graph of this type. The instance will be cleared. Directed graphs are not allowed. Raises ------ NetworkXException For a non-graphical degree sequence (i.e. one not realizable by some simple graph). Notes ----- The Havel-Hakimi algorithm constructs a simple graph by successively connecting the node of highest degree to other nodes of highest degree, resorting remaining nodes by degree, and repeating the process. The resulting graph has a high degree-associativity. Nodes are labeled 1,.., len(deg_sequence), corresponding to their position in deg_sequence. The basic algorithm is from Hakimi [1]_ and was generalized by Kleitman and Wang [2]_. References ---------- .. [1] Hakimi S., On Realizability of a Set of Integers as Degrees of the Vertices of a Linear Graph. I, Journal of SIAM, 10(3), pp. 496-506 (1962) .. [2] Kleitman D.J. and Wang D.L. Algorithms for Constructing Graphs and Digraphs with Given Valences and Factors Discrete Mathematics, 6(1), pp. 79-88 (1973) sInvalid degree sequences!Directed graphs are not supportediisNon-graphical integer sequenceN(iii(ii( Rt is_graphicalR.RR0RRR?tappendR=tpopRE(R!RRNR$titnum_degstdmaxtdsumRRtmodstubstsourcetmslentkttargettstubvalt stubtarget((st/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/generators/degree_seq.pyR ÅsL'   ,    cC sÆtjj|ƒst‚tjj|ƒs0t‚|dkrKtjƒ}nd \}}t|ƒt|ƒ}}t||ƒ}tj||ƒ}|dkr¡|Sd} gg} } xôt |ƒD]æ} d \} }| |krì|| }n| |kr|| } n| dks|dkr/tj dƒ‚n|| ||t| | ƒ}}} | dkr| j d|d| | fƒqÁ|dkrÁ| j d|| fƒqÁqÁW||krÉtj dƒ‚nt j | ƒt j | ƒd g| d}xË| rÁt j| ƒ\}}}|d9}|t| ƒt| ƒkrMtj dƒ‚nd}xát |ƒD]Ó}| r­| s| dd| ddkr­t j| ƒ\}}d}nt j| ƒ\}}}|dkrãtj dƒ‚n|j||ƒ|ddks|dkr`|d||f||<|d7}q`q`Wx_t |ƒD]Q}||}|ddkrwt j| |ƒqDt j| |d|dfƒqDW|dkr÷t j| ||fƒq÷q÷W|S( sReturn a directed graph with the given degree sequences. Parameters ---------- in_deg_sequence : list of integers Each list entry corresponds to the in-degree of a node. out_deg_sequence : list of integers Each list entry corresponds to the out-degree of a node. create_using : graph, optional (default DiGraph) Return graph of this type. The instance will be cleared. Returns ------- G : DiGraph A graph with the specified degree sequences. Nodes are labeled starting at 0 with an index corresponding to the position in deg_sequence Raises ------ NetworkXError If the degree sequences are not digraphical. See Also -------- configuration_model Notes ----- Algorithm as described by Kleitman and Wang [1]_. References ---------- .. [1] D.J. Kleitman and D.L. Wang Algorithms for Constructing Graphs and Digraphs with Given Valences and Factors Discrete Mathematics, 6(1), pp. 79-88 (1973) is;Invalid degree sequences. Sequence values must be positive.iÿÿÿÿs9Invalid degree sequences. Sequences must have equal sums.is Non-digraphical integer sequenceiN(ii(ii(iii(Rtutilstis_list_of_intstAssertionErrorRtDiGraphRR=RR?R.RRtheapqtheapifytheappopREtheappush(R#tout_deg_sequenceRtsumintsumouttnintnouttmaxnR$tmaxintstubheaptzeroheapRR'R&RXtfreeouttfreeinR\RZRTtstuboutt stubsourcetstubintstub((st/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/generators/degree_seq.pyR !sr(          % !       )   " c C sft|ƒ}|ddkr4d}tj|ƒ‚nt|ƒ|ddkrfd}tj|ƒ‚n|d k r|jƒrtjdƒ‚ntd„|Dƒdtƒ}t|ƒd}tj||ƒ}|}xct d|dƒD]N}|j ƒd} x+t ||| ƒD]} |j || ƒqW|| 7}qèWt|ƒt|ƒkrb|j dƒn|S( s Make a tree for the given degree sequence. A tree has #nodes-#edges=1 so the degree sequence must have len(deg_sequence)-sum(deg_sequence)/2=1 iis=Invalid degree sequence: sum of degrees must be even, not oddisbInvalid degree sequence: tree must have number of nodes equal to one less than the number of edgessDirected Graph not supportedcs s!|]}|dkr|VqdS(iN((Rts((st/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/generators/degree_seq.pys ©sR9N( R-RR.RRR0R>R4t path_graphR?RSREt remove_node( R!Rt degree_sumR2tdegRR$RLRYtnedgesR\((st/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/generators/degree_seq.pyR “s* i cC set|d|ƒ}x9t|ƒD]+}y|jƒSWqtjk rIqXqWtjd|ƒ‚dS(sReturn a simple random graph with the given degree sequence. If the maximum degree $d_m$ in the sequence is $O(m^{1/4})$ then the algorithm produces almost uniform random graphs in $O(m d_m)$ time where $m$ is the number of edges. Parameters ---------- sequence : list of integers Sequence of degrees seed : hashable object, optional Seed for random number generator tries : int, optional Maximum number of tries to create a graph Returns ------- G : Graph A graph with the specified degree sequence. Nodes are labeled starting at 0 with an index corresponding to the position in the sequence. Raises ------ NetworkXUnfeasible If the degree sequence is not graphical. NetworkXError If a graph is not produced in specified number of tries See Also -------- is_graphical, configuration_model Notes ----- The generator algorithm [1]_ is not guaranteed to produce a graph. References ---------- .. [1] Moshen Bayati, Jeong Han Kim, and Amin Saberi, A sequential algorithm for generating random graphs. Algorithmica, Volume 58, Number 4, 860-910, DOI: 10.1007/s00453-009-9340-1 Examples -------- >>> sequence = [1, 2, 2, 3] >>> G = nx.random_degree_sequence_graph(sequence) >>> sorted(d for n, d in G.degree()) [1, 2, 2, 3] Rs$failed to generate graph in %d triesN(tDegreeSequenceRandomGraphR?tgenerateRtNetworkXUnfeasibleR.(tsequenceRttriestDSRGttry_n((st/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/generators/degree_seq.pyR ½s4R|cB s_eZd d„Zd„Zd d„Zd„Zd„Zd„Zd„Z d„Z d„Z RS( cC s™tj|ƒs!tjdƒ‚n|dk r=tj|ƒnt|ƒ|_t|jƒd|_ yt |jƒ|_ Wnt k r”d|_ nXdS(Ns degree sequence is not graphicalg@i( RRQR~RRRRtdegreeR-tmR=RVt ValueError(tselfRƒR((st/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/generators/degree_seq.pyt__init__ýs  cC s¶tt|jƒƒ|_tjƒ|_|jj|jƒx<t|jj ƒƒD]%\}}|dkrP|j|=qPqPWt |jƒdkr¯|j ƒ|j ƒ|j ƒn|jS(Ni(tdictRRƒtremaining_degreeRtGraphtgraphtadd_nodes_fromRtitemsRtphase1tphase2tphase3(R†RR((st/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/generators/degree_seq.pyR} s"    cC sÁ|dk r|j||ƒn|j|dkr[|j|=|dk rn|j|ƒqnn|j|cd8<|j|dkrª|j|=|dk r½|j|ƒq½n|j|cd8=s(titerR‰tnexttany(R†tnodes((R†R;st/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/generators/degree_seq.pyt suitable_edge6s cC s®x§t|jjƒƒd|jdkr©tt|jdƒƒ\}}|jj||ƒrbqntjƒ|j ||ƒkr|jj ||ƒ|j ||ƒqqWdS(Ni( R-R‰R•RVR>RR‹thas_edgeRRNRER“(R†R;R<((st/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/generators/degree_seq.pyRŽ?s)cC sûxôt|jƒd|jkrött|jjƒƒƒd}xntr®ttj |jj ƒdƒƒ\}}|j j ||ƒr‰qAntjƒ|j ||ƒkrAPqAqAWtjƒ|j||ƒkr|j j||ƒ|j||ƒqqWdS(Ni(RR‰RVR”R=R•R4R>RtsampletkeysR‹RœRPRNRER“(R†R–R;R<((st/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/generators/degree_seq.pyRIs 'cC s't|jdƒ}tjg|D]-\}}|jj||ƒs||f^qƒ}xË|jr"|jƒstjdƒ‚nxStrÔt t j t |j ƒƒƒƒ\}}t j ƒ|j||ƒkr‚Pq‚q‚Wt j ƒ|j||ƒkrX|jj||ƒ|j||d|ƒqXqXWdS(Nisno suitable edges leftR’(RR‰RRŠR‹RœR›R~R4R>RtchoiceRtedgesRPRNRER“(R†tpotential_edgesR;R<tH((st/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/generators/degree_seq.pyRWs*   'N( t__name__t __module__RR‡R}R“RNRPR›RŽRR(((st/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/generators/degree_seq.pyR|ús     (#t__doc__t __future__RRct itertoolsRRRt ImportErrorRRBtoperatorRRtnetworkxRtnetworkx.utilsRt__all__t from_iterableRRtFalseRR,RRR4R R R R R tobjectR|(((st/private/var/folders/w6/vb91730s7bb1k90y_rnhql1dhvdd44/T/pip-build-w4MwvS/networkx/networkx/generators/degree_seq.pyts@        Fg]m ^ p *=