3
Mdp)                 @   s   d Z ddlmZ ddlmZ ddlZddlmZ ddlm	Z	 ddl
mZ dd	d
gZG dd deZdd Zdd Zdd Zdd Ze	dedd
 Zedd Zddd	ZdS )zHFunctions for measuring the quality of a partition (into
communities).

    )wraps)productN)NetworkXError)not_implemented_for)is_partitioncoverage
modularityperformancec                   s    e Zd ZdZ fddZ  ZS )NotAPartitionz6Raised if a given collection is not a partition.

    c                s   | d| }t  j| d S )Nz' is not a valid partition of the graph )super__init__)selfGZ
collectionmsg)	__class__ W/var/www/html/virt/lib/python3.6/site-packages/networkx/algorithms/community/quality.pyr      s    zNotAPartition.__init__)__name__
__module____qualname____doc__r   __classcell__r   r   )r   r   r
      s   r
   c                s   t   fdd}|S )a  Decorator to check that a valid partition is input to a function

    Raises :exc:`networkx.NetworkXError` if the partition is not valid.

    This decorator should be used on functions whose first two arguments
    are a graph and a partition of the nodes of that graph (in that
    order)::

        >>> @require_partition
        ... def foo(G, partition):
        ...     print("partition is valid!")
        ...
        >>> G = nx.complete_graph(5)
        >>> partition = [{0, 1}, {2, 3}, {4}]
        >>> foo(G, partition)
        partition is valid!
        >>> partition = [{0}, {2, 3}, {4}]
        >>> foo(G, partition)
        Traceback (most recent call last):
          ...
        networkx.exception.NetworkXError: `partition` is not a valid partition of the nodes of G
        >>> partition = [{0, 1}, {1, 2, 3}, {4}]
        >>> foo(G, partition)
        Traceback (most recent call last):
          ...
        networkx.exception.NetworkXError: `partition` is not a valid partition of the nodes of G

    c                 s$   t | d d  stjd | |S )N   z6`partition` is not a valid partition of the nodes of G)r   nxr   )argskw)funcr   r   new_func9   s    z#require_partition.<locals>.new_func)r   )r   r   r   )r   r   require_partition   s    	r   c                s   t  fdd|D S )aR  Returns the number of intra-community edges for a partition of `G`.

    Parameters
    ----------
    G : NetworkX graph.

    partition : iterable of sets of nodes
        This must be a partition of the nodes of `G`.

    The "intra-community edges" are those edges joining a pair of nodes
    in the same block of the partition.

    c             3   s   | ]} j |j V  qd S )N)Zsubgraphsize).0block)r   r   r   	<genexpr>S   s    z(intra_community_edges.<locals>.<genexpr>)sum)r   	partitionr   )r   r   intra_community_edgesE   s    r%   c             C   s(   | j  rtjntj}tj| ||dj S )a  Returns the number of inter-community edges for a prtition of `G`.
    according to the given
    partition of the nodes of `G`.

    Parameters
    ----------
    G : NetworkX graph.

    partition : iterable of sets of nodes
        This must be a partition of the nodes of `G`.

    The *inter-community edges* are those edges joining a pair of nodes
    in different blocks of the partition.

    Implementation note: this function creates an intermediate graph
    that may require the same amount of memory as that of `G`.

    )Zcreate_using)is_directedr   ZMultiDiGraphZ
MultiGraphZquotient_graphr   )r   r$   ZMGr   r   r   inter_community_edgesV   s    r'   c             C   s   t tj| |S )aH  Returns the number of inter-community non-edges according to the
    given partition of the nodes of `G`.

    `G` must be a NetworkX graph.

    `partition` must be a partition of the nodes of `G`.

    A *non-edge* is a pair of nodes (undirected if `G` is undirected)
    that are not adjacent in `G`. The *inter-community non-edges* are
    those non-edges on a pair of nodes in different blocks of the
    partition.

    Implementation note: this function creates two intermediate graphs,
    which may require up to twice the amount of memory as required to
    store `G`.

    )r'   r   Z
complement)r   r$   r   r   r   inter_community_non_edgesu   s    r(   Z
multigraphc             C   sD   t | |}t| |}t| }||d  }| j s8|d }|| | S )a  Returns the performance of a partition.

    The *performance* of a partition is the ratio of the number of
    intra-community edges plus inter-community non-edges with the total
    number of potential edges.

    Parameters
    ----------
    G : NetworkX graph
        A simple graph (directed or undirected).

    partition : sequence
        Partition of the nodes of `G`, represented as a sequence of
        sets of nodes. Each block of the partition represents a
        community.

    Returns
    -------
    float
        The performance of the partition, as defined above.

    Raises
    ------
    NetworkXError
        If `partition` is not a valid partition of the nodes of `G`.

    References
    ----------
    .. [1] Santo Fortunato.
           "Community Detection in Graphs".
           *Physical Reports*, Volume 486, Issue 3--5 pp. 75--174
           <https://arxiv.org/abs/0906.0612>

       r   )r%   r(   lenr&   )r   r$   intra_edgesZinter_edgesnZtotal_pairsr   r   r   r	      s    '

c             C   s   t | |}| j }|| S )a  Returns the coverage of a partition.

    The *coverage* of a partition is the ratio of the number of
    intra-community edges to the total number of edges in the graph.

    Parameters
    ----------
    G : NetworkX graph

    partition : sequence
        Partition of the nodes of `G`, represented as a sequence of
        sets of nodes. Each block of the partition represents a
        community.

    Returns
    -------
    float
        The coverage of the partition, as defined above.

    Raises
    ------
    NetworkXError
        If `partition` is not a valid partition of the nodes of `G`.

    Notes
    -----
    If `G` is a multigraph, the multiplicity of edges is counted.

    References
    ----------
    .. [1] Santo Fortunato.
           "Community Detection in Graphs".
           *Physical Reports*, Volume 486, Issue 3--5 pp. 75--174
           <https://arxiv.org/abs/0906.0612>

    )r%   Znumber_of_edges)r   r$   r+   Ztotal_edgesr   r   r   r      s    &
weightc                s   t |tst|}t |s&t | j rlt jdt jdtj	 dd  n4t j
d tj	 }|d d|d   fdd}tt||S )aU  Returns the modularity of the given partition of the graph.

    Modularity is defined in [1]_ as

    .. math::

        Q = \frac{1}{2m} \sum_{ij} \left( A_{ij} - \frac{k_ik_j}{2m}\right)
            \delta(c_i,c_j)

    where $m$ is the number of edges, $A$ is the adjacency matrix of
    `G`, $k_i$ is the degree of $i$ and $\delta(c_i, c_j)$
    is 1 if $i$ and $j$ are in the same community and 0 otherwise.

    According to [2]_ (and verified by some algebra) this can be reduced to

    .. math::
       Q = \sum_{c=1}^{n}
       \left[ \frac{L_c}{m} - \left( \frac{k_c}{2m} \right) ^2 \right]

    where the sum iterates over all communities $c$, $m$ is the number of edges,
    $L_c$ is the number of intra-community links for community $c$,
    $k_c$ is the sum of degrees of the nodes in community $c$.

    The second formula is the one actually used in calculation of the modularity.

    Parameters
    ----------
    G : NetworkX Graph

    communities : list or iterable of set of nodes
        These node sets must represent a partition of G's nodes.

    weight : string or None, optional (default="weight")
            The edge attribute that holds the numerical value used
            as a weight. If None or an edge does not have that attribute,
            then that edge has weight 1.

    Returns
    -------
    Q : float
        The modularity of the paritition.

    Raises
    ------
    NotAPartition
        If `communities` is not a partition of the nodes of `G`.

    Examples
    --------
    >>> import networkx.algorithms.community as nx_comm
    >>> G = nx.barbell_graph(3, 0)
    >>> nx_comm.modularity(G, [{0, 1, 2}, {3, 4, 5}])
    0.35714285714285715
    >>> nx_comm.modularity(G, nx_comm.label_propagation_communities(G))
    0.35714285714285715

    References
    ----------
    .. [1] M. E. J. Newman *Networks: An Introduction*, page 224.
       Oxford University Press, 2011.
    .. [2] Clauset, Aaron, Mark EJ Newman, and Cristopher Moore.
       "Finding community structure in very large networks."
       Physical review E 70.6 (2004). <https://arxiv.org/abs/cond-mat/0408187>
    )r-   r)   r   c                sr   t |  t fddj ddD }tfdd D }rZtfdd D n|}| ||   S )Nc             3   s    | ]\}}}| kr|V  qd S )Nr   )r    uvwt)commr   r   r"   G  s    z=modularity.<locals>.community_contribution.<locals>.<genexpr>r)   )datadefaultc             3   s   | ]} | V  qd S )Nr   )r    r.   )
out_degreer   r   r"   I  s    c             3   s   | ]} | V  qd S )Nr   )r    r.   )	in_degreer   r   r"   J  s    )setr#   edges)Z	communityZL_cZout_degree_sumZin_degree_sum)r   directedr5   mnormr4   r-   )r1   r   community_contributionE  s
    "z*modularity.<locals>.community_contribution)
isinstancelistr   r
   r&   dictr4   r5   r#   valuesZdegreemap)r   Zcommunitiesr-   Zdeg_sumr;   r   )r   r8   r5   r9   r:   r4   r-   r   r      s     A


	)r-   )r   	functoolsr   	itertoolsr   Znetworkxr   r   Znetworkx.utilsr   Z-networkx.algorithms.community.community_utilsr   __all__r
   r   r%   r'   r(   r	   r   r   r   r   r   r   <module>   s    

*5+