U
    td                     @   sF  d Z ddlmZ ddlmZ ddlmZmZ ddlm	Z	 ddl
mZ ddlmZ ddlmZ dd	lmZ dd
lmZ ddlmZ ddlmZ G dd dZG dd deZG dd dZG dd deZG dd dZG dd deZG dd deZdd Zd/ddZ d0d!d"Z!d1d#d$Z"d2d%d&Z#d'd( Z$d3d*d+Z%d4d,d-Z&d.S )5z$Classes related to graph clustering.    )deepcopy)StringIO)	GraphBasecommunity_to_membership)Configuration)UniqueIdGenerator)ClusterColoringPalette)CairoDendrogramDrawer)MatplotlibDendrogramDrawer)	Histogram)_get_wrapper_for_width)
deprecatedc                   @   s   e Zd ZdZd!ddZdd Zdd Zd	d
 Zdd Zdd Z	dd Z
edd Zedd Zdd Zdd Zd"ddZd#ddZdd  ZdS )$
Clusteringa
  Class representing a clustering of an arbitrary ordered set.

    This is now used as a base for L{VertexClustering}, but it might be
    useful for other purposes as well.

    Members of an individual cluster can be accessed by the C{[]} operator:

      >>> cl = Clustering([0,0,0,0,1,1,1,2,2,2,2])
      >>> cl[0]
      [0, 1, 2, 3]

    The membership vector can be accessed by the C{membership} property:

      >>> cl.membership
      [0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2]

    The number of clusters can be retrieved by the C{len} function:

      >>> len(cl)
      3

    You can iterate over the clustering object as if it were a regular list
    of clusters:

      >>> for cluster in cl:
      ...     print(" ".join(str(idx) for idx in cluster))
      ...
      0 1 2 3
      4 5 6
      7 8 9 10

    If you need all the clusters at once as lists, you can simply convert
    the clustering object to a list:

      >>> cluster_list = list(cl)
      >>> print(cluster_list)
      [[0, 1, 2, 3], [4, 5, 6], [7, 8, 9, 10]]
    Nc                 C   sN   t || _t| jdkr4tdd | jD d | _nd| _|rJ| j| dS )zConstructor.

        @param membership: the membership list -- that is, the cluster
          index in which each element of the set belongs to.
        @param params: additional parameters to be stored in this
          object's dictionary.r   c                 s   s   | ]}|d k	r|V  qd S N .0mr   r   J/home/sam/Atlas/atlas_env/lib/python3.8/site-packages/igraph/clustering.py	<genexpr>D   s      z&Clustering.__init__.<locals>.<genexpr>   N)list_membershiplenmax_len__dict__update)self
membershipparamsr   r   r   __init__;   s    
zClustering.__init__c                    s2    dk s | j krtd fddt| jD S )zReturns the members of the specified cluster.

        @param idx: the index of the cluster
        @return: the members of the specified cluster as a list
        @raise IndexError: if the index is out of boundsr   zcluster index out of rangec                    s   g | ]\}}| kr|qS r   r   )r   ieidxr   r   
<listcomp>S   s      z*Clustering.__getitem__.<locals>.<listcomp>)r   
IndexError	enumerater   r   r%   r   r$   r   __getitem__K   s    zClustering.__getitem__c                 C   s>   dd t | jD }t| jD ]\}}|| | qt|S )zIterates over the clusters in this clustering.

        This method will return a generator that generates the clusters
        one by one.c                 S   s   g | ]}g qS r   r   r   _r   r   r   r&   Z   s     z'Clustering.__iter__.<locals>.<listcomp>)ranger   r(   r   appenditer)r   clustersr%   clusterr   r   r   __iter__U   s    zClustering.__iter__c                 C   s   | j S )zQReturns the number of clusters.

        @return: the number of clusters
        )r   r   r   r   r   __len___   s    zClustering.__len__c                 C   s   | j dddS )Nr   N   	verbositywidthsummaryr3   r   r   r   __str__f   s    zClustering.__str__c                 C   s   t | j| S )zFReturns a L{Cover} that contains the same clusters as this clustering.)Cover_graphr3   r   r   r   as_coveri   s    zClustering.as_coverc                 O   s   t | |f||S )a5  Compares this clustering to another one using some similarity or
        distance metric.

        This is a convenience method that simply calls L{compare_communities}
        with the two clusterings as arguments. Any extra positional or keyword
        argument is also forwarded to L{compare_communities}.)compare_communities)r   otherargskwdsr   r   r   
compare_tom   s    zClustering.compare_toc                 C   s   | j dd S )zReturns the membership vector.N)r   r3   r   r   r   r   v   s    zClustering.membershipc                 C   s
   t | jS )z:Returns the number of elements covered by this clustering.r   r   r3   r   r   r   n{   s    zClustering.nc                 C   s   t | | S zjReturns the size of a given cluster.

        @param idx: the cluster in which we are interested.
        r   r)   r   r   r   size   s    zClustering.sizec                    sL   dgt |   | jD ]}|dk	r |  d7  < q|rH fdd|D S  S )Returns the size of given clusters.

        The indices are given as positional arguments. If there are no
        positional arguments, the function will return the sizes of all clusters.
        r   Nr   c                    s   g | ]} | qS r   r   r   r%   countsr   r   r&      s     z$Clustering.sizes.<locals>.<listcomp>rD   )r   rA   xr   rK   r   sizes   s    
zClustering.sizesr   c                 C   s   t ||  S zReturns the histogram of cluster sizes.

        @param bin_width: the bin width of the histogram
        @return: a L{Histogram} object
        r   rN   r   Z	bin_widthr   r   r   size_histogram   s    zClustering.size_histogramr   c                 C   s   t  }tdt| jt| f |d |dk r8|  S ttt| }t|d|d  d}t| 	 D ].\}}d||f |_
td|||d qh|  S )	a  Returns the summary of the clustering.

        The summary includes the number of items and clusters, and also the
        list of members for each of the clusters if the verbosity is nonzero.

        @param verbosity: determines whether the cluster members should be
          printed. Zero verbosity prints the number of items and clusters only.
        @return: the summary of the clustering as a string.
        z+Clustering with %d elements and %d clustersfiler       subsequent_indent[%*d] 
)r   printr   r   getvaluestripstrr   r(   _formatted_cluster_iteratorinitial_indentjoinwrapr   r7   r8   outndigitswrapperr%   r1   r   r   r   r:      s"    
	zClustering.summaryc                 c   s$   | D ]}d dd |D V  qdS )aIterates over the clusters and formats them into a string to be
        presented in the summary., c                 s   s   | ]}t |V  qd S r   r^   r   memberr   r   r   r      s     z9Clustering._formatted_cluster_iterator.<locals>.<genexpr>Nra   r   r1   r   r   r   r_      s    z&Clustering._formatted_cluster_iterator)N)r   )r   N)__name__
__module____qualname____doc__r!   r*   r2   r4   r;   r>   rC   propertyr   rE   rH   rN   rR   r:   r_   r   r   r   r   r      s"   '


	



 r   c                       s   e Zd ZdZdZd fdd	Zed ddZdd Zd!d	d
Z	dd Z
edd ZeZedd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Z  ZS )"VertexClusteringa  The clustering of the vertex set of a graph.

    This class extends L{Clustering} by linking it to a specific L{Graph} object
    and by optionally storing the modularity score of the clustering.
    It also provides some handy methods like getting the subgraph corresponding
    to a cluster and such.

    @note: since this class is linked to a L{Graph}, destroying the graph by the
      C{del} operator does not free the memory occupied by the graph if there
      exists a L{VertexClustering} that references the L{Graph}.
    Nc                    s|   |dkr"t  dg|  | n&t|| kr:tdt  || || _|| _|dk| _|dkrni | _n
t	|| _dS )a7  Creates a clustering object for a given graph.

        @param graph: the graph that will be associated to the clustering
        @param membership: the membership list. The length of the list must
          be equal to the number of vertices in the graph. If C{None}, every
          vertex is assumed to belong to the same cluster.
        @param modularity: the modularity score of the clustering. If C{None},
          it will be calculated when needed.
        @param params: additional parameters to be stored in this object.
        @param modularity_params: arguments that should be passed to
          L{Graph.modularity} when the modularity is (re)calculated. If the
          original graph was weighted, you should pass a dictionary
          containing a C{weight} key with the appropriate value here.
        Nr   z"membership list has invalid length)
superr!   vcountr   
ValueErrorr=   _modularity_modularity_dirty_modularity_paramsdict)r   graphr   
modularityr    modularity_params	__class__r   r   r!      s    
zVertexClustering.__init__c                    s   ddl m   dd  fddzt}d}W n tk
rH   d}Y nX d	kr^|j| }nJ|rtfd
d|j| D }n"tfdd|j| D }t d	d	< fdd|D }| ||d	|S )a  Creates a vertex clustering based on the value of a vertex attribute.

        Vertices having the same attribute will correspond to the same cluster.

        @param graph: the graph on which we are working
        @param attribute: name of the attribute on which the clustering
            is based.
        @param intervals: for numeric attributes, you can either pass a single
            number or a list of numbers here. A single number means that the
            vertices will be put in bins of that width and vertices ending up
            in the same bin will be in the same cluster. A list of numbers
            specify the bin positions explicitly; e.g., C{[10, 20, 30]} means
            that there will be four categories: vertices with the attribute
            value less than 10, between 10 and 20, between 20 and 30 and over 30.
            Intervals are closed from the left and open from the right.
        @param params: additional parameters to be stored in this object.

        @return: a new VertexClustering object
        r   bisectc                 S   s   | dkrdS t | | S )z2Safe integer division that handles None gracefullyN)int)rM   yr   r   r   
safeintdiv  s    z2VertexClustering.FromAttribute.<locals>.safeintdivc                    s   |dkrdS  | |S )z0Safe list bisection that handles None gracefullyNr   )	intervalsrM   r   r   r   
safebisect  s    z2VertexClustering.FromAttribute.<locals>.safebisectTFNc                    s   g | ]} |qS r   r   r   rM   )r   r   r   r   r&   '  s     z2VertexClustering.FromAttribute.<locals>.<listcomp>c                    s   g | ]}| qS r   r   r   )r   r   r   r   r&   *  s     c                    s   g | ]} | qS r   r   r   r"   idgenr   r   r&   .  s     )r   r/   	TypeErrorvsr   floatr   )clsr{   	attributer   r    r,   iterableZvecr   )r   r   r   r   r   r   FromAttribute   s&    
zVertexClustering.FromAttributec                 C   s   t | j| S )zTReturns a L{VertexCover} that contains the same clusters as this
        clustering.)VertexCoverr=   r3   r   r   r   r>   1  s    zVertexClustering.as_coverc                 C   s0   | j  }|| j| |dk	r,|j|d |S )a  Returns a graph where each cluster is contracted into a single
        vertex.

        In the resulting graph, vertex M{i} represents cluster M{i} in this
        clustering. Vertex M{i} and M{j} will be connected if there was
        at least one connected vertex pair M{(a, b)} in the original graph such
        that vertex M{a} was in cluster M{i} and vertex M{b} was in cluster
        M{j}.

        @param combine_vertices: specifies how to derive the attributes of
          the vertices in the new graph from the attributes of the old ones.
          See L{Graph.contract_vertices()<igraph._igraph.GraphBase.contract_vertices>}
          for more details.
        @param combine_edges: specifies how to derive the attributes of the
          edges in the new graph from the attributes of the old ones. See
          L{Graph.simplify()<igraph._igraph.GraphBase.simplify>} for more details.
          If you specify C{False} here, edges will not be combined, and the
          number of edges between the vertices representing the original
          clusters will be equal to the number of edges between the members of
          those clusters in the original graph.

        @return: the new graph.
        F)combine_edges)r{   copyZcontract_verticesr   simplify)r   Zcombine_verticesr   resultr   r   r   cluster_graph6  s
    
zVertexClustering.cluster_graphc                    s   | j   fdd| j D S )wReturns a boolean vector where element M{i} is C{True} iff edge
        M{i} lies between clusters, C{False} otherwise.c                    s    g | ]\}} |  | kqS r   r   r   Zv1Zv2r   r   r   r&   X  s    z-VertexClustering.crossing.<locals>.<listcomp>r   r{   get_edgelistr3   r   r   r   crossingT  s    
zVertexClustering.crossingc                 C   s   | j r|  S | jS )zReturns the modularity score)rx   _recalculate_modularity_saferw   r3   r   r   r   r|   \  s    zVertexClustering.modularityc                 C   s   | j S z*Returns the graph belonging to this objectr=   r3   r   r   r   r{   e  s    zVertexClustering.graphc                 C   s"   | j j| jf| j| _d| _| jS )aw  Recalculates the stored modularity value.

        This method must be called before querying the modularity score of the
        clustering through the class member C{modularity} or C{q} if the
        graph has been modified (edges have been added or removed) since the
        creation of the L{VertexClustering} object.

        @return: the new modularity score
        F)r=   r|   r   ry   rw   rx   r3   r   r   r   recalculate_modularityj  s    
z'VertexClustering.recalculate_modularityc                 C   s<   z.z|  W W  S  tk
r*   Y W 
dS X W 5 d| _ X dS )zRecalculates the stored modularity value and swallows all exceptions
        raised by the modularity function (if any).

        @return: the new modularity score or C{None} if the modularity function
        could not be calculated.
        FN)rx   r   	Exceptionr3   r   r   r   r   z  s
    z-VertexClustering._recalculate_modularity_safec                 C   s   | j | | S a  Get the subgraph belonging to a given cluster.

        Precondition: the vertex set of the graph hasn't been modified since the
        moment the cover was constructed.

        @param idx: the cluster index
        @return: a copy of the subgraph
        r=   subgraphr)   r   r   r   r     s    	zVertexClustering.subgraphc                    s    fdd D S )Gets all the subgraphs belonging to each of the clusters.

        Precondition: the vertex set of the graph hasn't been modified since the
        moment the cover was constructed.

        @return: a list containing copies of the subgraphs
        c                    s   g | ]} j |qS r   r   r   clr3   r   r   r&     s     z.VertexClustering.subgraphs.<locals>.<listcomp>r   r3   r   r3   r   	subgraphs  s    zVertexClustering.subgraphsc                 C   s    |   }t|}| ||S )ar  Returns the largest cluster of the clustered graph.

        The largest cluster is a cluster for which no larger cluster exists in
        the clustering. It may also be known as the I{giant community} if the
        clustering represents the result of a community detection function.

        Precondition: the vertex set of the graph hasn't been modified since the
        moment the cover was constructed.

        @note: there can be multiple largest clusters, this method will return
          the copy of an arbitrary one if there are multiple largest clusters.

        @return: a copy of the largest cluster.
        )rN   r   r   index)r   ssmax_sizer   r   r   giant  s    zVertexClustering.giantc                    s   ddl m} d|krDd| j krD||   fdd|  D |d< |dd}|dkrhtt| |d< d	|krt	 d
 r| |d	< nt
|d	 | |d	< d|kr| j|d< | jj||f||}|S )aL	  Plots the clustering to the given Cairo context or matplotlib Axes.

        This is done by calling L{Graph.__plot__()} with the same arguments, but
        coloring the graph vertices according to the current clustering (unless
        overridden by the C{vertex_color} argument explicitly).

        This method understands all the positional and keyword arguments that
        are understood by L{Graph.__plot__()}, only the differences will be
        highlighted here:

          - C{mark_groups}: whether to highlight some of the vertex groups by
            colored polygons. Besides the values accepted by L{Graph.__plot__}
            (i.e., a dict mapping colors to vertex indices, a list containing
            lists of vertex indices, or C{False}), the following are also
            accepted:

              - C{True}: all the groups will be highlighted, the colors matching
                the corresponding color indices from the current palette
                (see the C{palette} keyword argument of L{Graph.__plot__}.

              - A dict mapping cluster indices or tuples of vertex indices to
                color names.  The given clusters or vertex groups will be
                highlighted by the given colors.

              - A list of cluster indices. This is equivalent to passing a
                dict mapping numeric color indices from the current palette
                to cluster indices; therefore, the cluster referred to by element
                I{i} of the list will be highlighted by color I{i} from the
                palette.

            The value of the C{plotting.mark_groups} configuration key is also
            taken into account here; if that configuration key is C{True} and
            C{mark_groups} is not given explicitly, it will automatically be set
            to C{True}.

            In place of lists of vertex indices, you may also use L{VertexSeq}
            instances.

            In place of color names, you may also use color indices into the
            current palette. C{None} as a color name will mean that the
            corresponding group is ignored.

          - C{palette}: the palette used to resolve numeric color indices to RGBA
            values. By default, this is an instance of L{ClusterColoringPalette}.

        @see: L{Graph.__plot__()} for more supported keyword arguments.
        r   )default_edge_colors
edge_colorcolorc                    s   g | ]} | qS r   r   r   Zis_crossingcolorsr   r   r&     s    z-VertexClustering.__plot__.<locals>.<listcomp>paletteNmark_groupsplotting.mark_groupsvertex_color)igraph.drawing.colorsr   r{   edge_attributesr   getr   r   r   instance&_handle_mark_groups_arg_for_clusteringr   r=   __plot__)r   backendcontextrA   rB   r   r   r   r   r   r   r     s(    0


 
zVertexClustering.__plot__c                 #   s`   | j  r<| j jd  | D ]}d fdd|D V  qn | D ]}ddd |D V  q@dS )rg   namerh   c                 3   s   | ]}t  | V  qd S r   ri   rj   namesr   r   r     s     z?VertexClustering._formatted_cluster_iterator.<locals>.<genexpr>c                 s   s   | ]}t |V  qd S r   ri   rj   r   r   r   r     s     Nr=   Zis_namedr   ra   rm   r   r   r   r_     s    
z,VertexClustering._formatted_cluster_iterator)NNNN)NN)NN)rn   ro   rp   rq   Z_default_paletter!   classmethodr   r>   r   r   rr   r|   qr{   r   r   r   r   r   r   r_   __classcell__r   r   r~   r   rs      s0       %5



Krs   c                   @   sx   e Zd ZdZdd ZedddZdd Zd	d
 ZdddZ	dddZ
dd Zedd Zedd Zejdd ZdS )
Dendrograma  The hierarchical clustering (dendrogram) of some dataset.

    A hierarchical clustering means that we know not only the way the
    elements are separated into groups, but also the exact history of
    how individual elements were joined into larger subgroups.

    This class internally represents the hierarchy by a matrix with n rows
    and 2 columns -- or more precisely, a list of lists of size 2. This is
    exactly the same as the original format used by C{igraph}'s C core.
    The M{i}th row of the matrix contains the indices of the two clusters
    being joined in time step M{i}. The joint group will be represented by
    the ID M{n+i}, with M{i} starting from one. The ID of the joint group
    will be referenced in the upcoming steps instead of any of its individual
    members. So, IDs less than or equal to M{n} (where M{n} is the number of
    rows in the matrix) mean the original members of the dataset (with ID
    from 0 to M{n}), while IDs up from M{n+1} mean joint groups. As an
    example, take a look at the dendrogram and the internal representation of
    a given clustering of five nodes::

      0 -+
         |
      1 -+-+
           |
      2 ---+-+        <====>   [[0, 1], [3, 4], [2, 5], [6, 7]]
             |
      3 -+   |
         |   |
      4 -+---+---
    c                 C   sN   dd |D | _ t| j | _| jr>t| j d | j d | _nd| _d| _dS )zmCreates a hierarchical clustering.

        @param merges: the merge history either in matrix or tuple formatc                 S   s   g | ]}t |qS r   )tupler   pairr   r   r   r&   -  s     z'Dendrogram.__init__.<locals>.<listcomp>   r   N)_mergesr   _nmergesr   _nitems_names)r   mergesr   r   r   r!   )  s    zDendrogram.__init__Nc           
   	   C   s   |dkrt | d }t|}t|}t| D ]r\}}|\}}z2|| ||  }}	|| ||	 f||< d||	< W n$ tk
r   tdd|  Y nX || q,dd |D S )zConverts the matrix representation of a clustering to a tuple
        representation.

        @param merges: the matrix representation of the clustering
        @return: the tuple representation of the clustering
        Nr   z&malformed matrix, subgroup referenced zbefore being created in step %dc                 S   s   g | ]}|d k	r|qS r   r   r   r   r   r   r&   M  s      z<Dendrogram._convert_matrix_to_tuple_repr.<locals>.<listcomp>)r   r-   r(   r'   rv   r.   )
r   rE   Z
tuple_reprZidxsZrowidxrowr"   jZidxiZidxjr   r   r   _convert_matrix_to_tuple_repr5  s$    
z(Dendrogram._convert_matrix_to_tuple_reprc                 C   s|   g }t  }tt| j| j D ]X}||kr,q|g}|r| }|| || jk r^|| q2|| j	|| j   q2q|S )a  Conducts an inorder traversal of the merge tree.

        The inorder traversal returns the nodes on the last level in the order
        they should be drawn so that no edges cross each other.

        @return: the result of the inorder traversal in a list.)
setreversedr-   r   r   popaddr.   extendr   )r   r   Z
seen_nodesZ
node_indexstacklastr   r   r   _traverse_inorderO  s    

zDendrogram._traverse_inorderc                 C   s   | j ddS )Nr   )r7   r9   r3   r   r   r   r;   l  s    zDendrogram.__str__newickc                 C   s   |dkr| j | j }| jdkr,tt|}n
t| j}t||k rb|dd t|t| D  t| j| j D ]:\}\}}d|| || || f ||< d ||< ||< qp|d d S t	d| dS )	aX  Formats the dendrogram in a foreign format.

        Currently only the Newick format is supported.

        Example:

            >>> d = Dendrogram([(2, 3), (0, 1), (4, 5)])
            >>> d.format()
            '((2,3)4,(0,1)5)6;'
            >>> d.names = list("ABCDEFG")
            >>> d.format()
            '((C,D)E,(A,B)F)G;'
        r   Nc                 s   s   | ]
}d V  qdS  Nr   r+   r   r   r   r     s     z$Dendrogram.format.<locals>.<genexpr>z	(%s,%s)%sr   ;zunsupported format: %r)
r   r   r   r   r-   r   r   r(   r   rv   )r   formatrE   Znodeskr"   r   r   r   r   r   o  s    

 zDendrogram.formatr   (   c                 C   s  t  }td| j| jf |d | jdks:|dk s:| j|krF|  S td|d dg| j }|  }d}d}d}t|D ]6\}	}
|||
< t|
||	< |t	|t
||	 d 7 }qzt	|d }td|d  ||d d}| j}|| jk rdg| }|D ]}|dkrd	||< qd|}t|d D ]}t||d q(d}|| jk r| j| \}}||ks||krrq|d7 }|| ||  }}d
\||< ||< ||kr|| }}||| d  d|| d  }d| |||d < |d7 }q@||7 }td||d q|  S )a  Returns the summary of the dendrogram.

        The summary includes the number of leafs and branches, and also an
        ASCII art representation of the dendrogram unless it is too large.

        @param verbosity: determines whether the ASCII representation of the
          dendrogram should be printed. Zero verbosity prints only the number
          of leafs and branches.
        @param max_leaf_count: the maximal number of leafs to print in the
          ASCII representation. If the dendrogram has more leafs than this
          limit, the ASCII representation will not be printed even if the
          verbosity is larger than or equal to 1.
        @return: the summary of the dendrogram as a string.
        z"Dendrogram, %d elements, %d mergesrS   r   r   r   Nr   rU   |)r   r   -z`%s')r   r[   r   r   r\   r]   r   r(   r^   r   r   ra   r-   r   r.   )r   r7   Zmax_leaf_countrd   Z	positionsZinorderZdistanceZlevel_distanceZnextpr%   elementr8   ZmidxZmax_community_idxZ
char_arraypositionZchar_strr,   Z	cidx_incrZid1Zid2Zpos1pos2dashesr   r   r   r:     sd    	




zDendrogram.summaryc                 O   sh   |dkrt |}nD|dd}|dd}|dkr:td|dkrJtdt|||}|j| f| dS )a  Draws the dendrogram on the given Cairo context or matplotlib Axes.

        Supported keyword arguments are:

          - C{orientation}: the orientation of the dendrogram. Must be one of
            the following values: C{left-right}, C{bottom-top}, C{right-left}
            or C{top-bottom}. Individual elements are always placed at the
            former edge and merges are performed towards the latter edge.
            Possible aliases: C{horizontal} = C{left-right},
            C{vertical} = C{bottom-top}, C{lr} = C{left-right},
            C{rl} = C{right-left}, C{tb} = C{top-bottom}, C{bt} = C{bottom-top}.
            The default is C{left-right}.

        
matplotlibbboxNr   z bbox is required for Cairo plotsz#palette is required for Cairo plots)r
   r   rv   r	   Zdraw)r   r   r   rA   rB   Zdrawerr   r   r   r   r   r     s    
zDendrogram.__plot__c                 C   s
   t | jS )z-Returns the performed merges in matrix format)r   r   r3   r   r   r   r     s    zDendrogram.mergesc                 C   s   | j S )z0Returns the names of the nodes in the dendrogram)r   r3   r   r   r   r     s    zDendrogram.namesc                 C   s   |dkrd| _ dS t|}t|| jk r6td| j | j| j }|d| | _ t| j |k r| j dd t|t| j  D  dS )z-Sets the names of the nodes in the dendrogramNzmust specify at least %d namesc                 s   s   | ]
}d V  qdS r   r   r+   r   r   r   r     s     z#Dendrogram.names.<locals>.<genexpr>)r   r   r   r   rv   r   r   r-   )r   itemsrE   r   r   r   r     s    )N)r   )r   r   )rn   ro   rp   rq   r!   staticmethodr   r   r;   r   r:   r   rr   r   r   setterr   r   r   r   r   
  s   

P

r   c                       sN   e Zd ZdZd fdd	ZdddZedd Zejd	d Zd
d Z	  Z
S )VertexDendrogramz[The dendrogram resulting from the hierarchical clustering of the
    vertex set of a graph.Nc                    s6   t  | || _|| _|dkr(i | _n
t|| _dS )a  Creates a dendrogram object for a given graph.

        @param graph: the graph that will be associated to the clustering
        @param merges: the merges performed given in matrix form.
        @param optimal_count: the optimal number of clusters where the
          dendrogram should be cut. This is a hint usually provided by the
          clustering algorithm that produces the dendrogram. C{None} means
          that such a hint is not available; the optimal count will then be
          selected based on the modularity in such a case.
        @param params: additional parameters to be stored in this object.
        @param modularity_params: arguments that should be passed to
          L{Graph.modularity} when the modularity is (re)calculated. If the
          original graph was weighted, you should pass a dictionary
          containing a C{weight} key with the appropriate value here.
        N)rt   r!   r=   _optimal_country   rz   )r   r{   r   optimal_countr    r}   r~   r   r   r!     s    zVertexDendrogram.__init__c                    sT   |dkr| j }| j }t  t| j||| } fdd|D }t| j|| jdS )a}  Cuts the dendrogram at the given level and returns a corresponding
        L{VertexClustering} object.

        @param n: the desired number of clusters. Merges are replayed from the
          beginning until the membership vector has exactly M{n} distinct elements
          or until there are no more recorded merges, whichever happens first.
          If C{None}, the optimal count hint given by the clustering algorithm
          will be used If the optimal count was not given either, it will be
          calculated by selecting the level where the modularity is maximal.
        @return: a new L{VertexClustering} object.
        Nc                    s   g | ]} | qS r   r   r   r   r   r   r&   A  s     z2VertexDendrogram.as_clustering.<locals>.<listcomp>)r}   )r   r=   ru   r   r   r   rs   ry   )r   rE   Znum_eltsr   r   r   r   as_clustering0  s    
  zVertexDendrogram.as_clusteringc                 C   s   | j dk	r| j S | j }|dkr&dS d|t| j  }}tt|d t| jd D ]8}t| j||}| jj|f| j	}||krV|| }|}qV|| _ |S )af  Returns the optimal number of clusters for this dendrogram.

        If an optimal count hint was given at construction time, this
        property simply returns the hint. If such a count was not given,
        this method calculates the optimal number of clusters by maximizing
        the modularity along all the possible cuts in the dendrogram.
        Nr   r   )
r   r=   ru   r   r   r-   minr   r|   ry   )r   rE   Zmax_qr   stepZmembsr   r   r   r   r   F  s    	

 zVertexDendrogram.optimal_countc                 C   s   t t|d| _d S )Nr   )r   r   r   )r   valuer   r   r   r   a  s    c           	      O   sn   ddl m} G dd d|}|| jj|}dd |D | _dd t| jD | _tj| ||f||}| `|S )zDraws the vertex dendrogram on the given Cairo context or matplotlib Axes

        See L{Dendrogram.__plot__} for the list of supported keyword
        arguments.r   )AttributeCollectorBasec                   @   s   e Zd ZdZdZdS )z6VertexDendrogram.__plot__.<locals>.VisualVertexBuilderZvertex_N)rn   ro   rp   Z_kwds_prefixlabelr   r   r   r   VisualVertexBuilderl  s   r   c                 S   s   g | ]
}|j qS r   )r   )r   Zvertexr   r   r   r&   q  s     z-VertexDendrogram.__plot__.<locals>.<listcomp>c                 S   s$   g | ]\}}|d k	r|nt |qS r   ri   )r   r%   r   r   r   r   r&   r  s   )Zigraph.drawing.metamagicr   r=   r   r   r(   r   r   )	r   r   r   rA   rB   r   r   Zbuilderr   r   r   r   r   e  s    zVertexDendrogram.__plot__)NNN)N)rn   ro   rp   rq   r!   r   rr   r   r   r   r   r   r   r~   r   r     s        


r   c                   @   s~   e Zd ZdZdddZdd Zdd Zd	d
 Zdd Ze	dd Z
e	dd Zdd Zdd ZdddZdddZdd ZdS ) r<   a<  Class representing a cover of an arbitrary ordered set.

    Covers are similar to clusterings, but each element of the set may
    belong to more than one cluster in a cover, and elements not belonging
    to any cluster are also allowed.

    L{Cover} instances provide a similar API as L{Clustering} instances;
    for instance, iterating over a L{Cover} will iterate over the clusters
    just like with a regular L{Clustering} instance. However, they are not
    derived from each other or from a common superclass, and there might
    be functions that exist only in one of them or the other.

    Clusters of an individual cover can be accessed by the C{[]} operator:

      >>> cl = Cover([[0,1,2,3], [2,3,4], [0,1,6]])
      >>> cl[0]
      [0, 1, 2, 3]

    The membership vector can be accessed by the C{membership} property.
    Note that contrary to L{Clustering} instances, the membership vector
    will contain lists that contain the cluster indices each item belongs
    to:

      >>> cl.membership
      [[0, 2], [0, 2], [0, 1], [0, 1], [1], [], [2]]

    The number of clusters can be retrieved by the C{len} function:

      >>> len(cl)
      3

    You can iterate over the cover as if it were a regular list of
    clusters:

      >>> for cluster in cl:
      ...     print(" ".join(str(idx) for idx in cluster))
      ...
      0 1 2 3
      2 3 4
      0 1 6

    If you need all the clusters at once as lists, you can simply convert
    the cover to a list:

      >>> cluster_list = list(cl)
      >>> print(cluster_list)
      [[0, 1, 2, 3], [2, 3, 4], [0, 1, 6]]

    L{Clustering} objects can readily be converted to L{Cover} objects
    using the constructor:

      >>> clustering = Clustering([0, 0, 0, 0, 1, 1, 1, 2, 2, 2])
      >>> cover = Cover(clustering)
      >>> list(clustering) == list(cover)
      True
    r   c                 C   sX   dd |D | _ ztdd | j D | _W n tk
rD   d| _Y nX t|| j| _dS )a  Constructs a cover with the given clusters.

        @param clusters: the clusters in this cover, as a list or iterable.
          Each cluster is specified by a list or tuple that contains the
          IDs of the items in this cluster. IDs start from zero.

        @param n: the total number of elements in the set that is covered
          by this cover. If it is less than the number of unique elements
          found in all the clusters, we will simply use the number of unique
          elements, so it is safe to leave this at zero. You only have to
          specify this parameter if there are some elements that are covered
          by none of the clusters.
        c                 S   s   g | ]}t |qS r   )r   r   r1   r   r   r   r&     s     z"Cover.__init__.<locals>.<listcomp>c                 s   s   | ]}|rt |d  V  qdS )r   N)r   r   r   r   r   r     s      z!Cover.__init__.<locals>.<genexpr>r   N)	_clustersr   _nrv   )r   r0   rE   r   r   r   r!     s    zCover.__init__c                 C   s
   | j | S )z)Returns the cluster with the given index.)r   )r   r   r   r   r   r*     s    zCover.__getitem__c                 C   s
   t | jS )z)Iterates over the clusters in this cover.)r/   r   r3   r   r   r   r2     s    zCover.__iter__c                 C   s
   t | jS )z-Returns the number of clusters in this cover.r   r   r3   r   r   r   r4     s    zCover.__len__c                 C   s   | j dddS )z-Returns a string representation of the cover.r   r5   r6   r9   r3   r   r   r   r;     s    zCover.__str__c                 C   sB   dd t | jD }t| D ] \}}|D ]}|| | q(q|S )zReturns the membership vector of this cover.

        The membership vector of a cover covering I{n} elements is a list of
        length I{n}, where element I{i} contains the cluster indices of the
        I{i}th item.
        c                 S   s   g | ]}g qS r   r   r+   r   r   r   r&     s     z$Cover.membership.<locals>.<listcomp>)r-   r   r(   r.   )r   r   r%   r1   itemr   r   r   r     s
    zCover.membershipc                 C   s   | j S )z@Returns the number of elements in the set covered by this cover.)r   r3   r   r   r   rE     s    zCover.nc                 C   s   t | | S rF   rG   r)   r   r   r   rH     s    z
Cover.sizec                    s$   |r fdd|D S dd  D S )rI   c                    s   g | ]}t  j| qS r   r   rJ   r3   r   r   r&      s     zCover.sizes.<locals>.<listcomp>c                 S   s   g | ]}t |qS r   rG   r   r   r   r   r&     s     r   )r   rA   r   r3   r   rN     s    zCover.sizesr   c                 C   s   t ||  S rO   rP   rQ   r   r   r   rR     s    zCover.size_histogramNc                 C   s   t  }tdt|  |d |dk r.|  S ttt| }t|d|d  d}t|  D ].\}}d||f |_	td
|||d q^|  S )	a  Returns the summary of the cover.

        The summary includes the number of items and clusters, and also the
        list of members for each of the clusters if the verbosity is nonzero.

        @param verbosity: determines whether the cluster members should be
          printed. Zero verbosity prints the number of items and clusters only.
        @return: the summary of the cover as a string.
        zCover with %d clustersrS   r   rU   rV   rW   rY   rZ   )r   r[   r   r\   r]   r^   r   r(   r_   r`   ra   rb   rc   r   r   r   r:     s    
zCover.summaryc                 c   s$   | D ]}d dd |D V  qdS )rg   rh   c                 s   s   | ]}t |V  qd S r   ri   rj   r   r   r   r   (  s     z4Cover._formatted_cluster_iterator.<locals>.<genexpr>Nrl   rm   r   r   r   r_   $  s    z!Cover._formatted_cluster_iterator)r   )r   )r   N)rn   ro   rp   rq   r!   r*   r2   r4   r;   rr   r   rE   rH   rN   rR   r:   r_   r   r   r   r   r<     s   9





r<   c                       sV   e Zd ZdZd fdd	Zdd Zedd Zd	d
 Zdd Z	dd Z
dd Z  ZS )r   a  The cover of the vertex set of a graph.

    This class extends L{Cover} by linking it to a specific L{Graph} object.
    It also provides some handy methods like getting the subgraph corresponding
    to a cluster and such.

    @note: since this class is linked to a L{Graph}, destroying the graph by the
      C{del} operator does not free the memory occupied by the graph if there
      exists a L{VertexCover} that references the L{Graph}.
    Nc                    sJ   |dkrt | g}t j|| d | j| kr@td|| _dS )a  Creates a cover object for a given graph.

        @param graph: the graph that will be associated to the cover
        @param clusters: the list of clusters. If C{None}, it is assumed
          that there is only a single cluster that covers the whole graph.
        N)rE   zOcluster list contains vertex ID larger than the number of vertices in the graph)r-   ru   rt   r!   r   rv   r=   )r   r{   r0   r~   r   r   r!   7  s    zVertexCover.__init__c                    s(   dd | j D   fdd| j D S )r   c                 S   s   g | ]}t |qS r   )	frozensetr   r   r   r   r&   M  s     z(VertexCover.crossing.<locals>.<listcomp>c                    s"   g | ]\}} |   | qS r   )
isdisjointr   r   r   r   r&   N  s   r   r3   r   r   r   r   J  s    
zVertexCover.crossingc                 C   s   | j S r   r   r3   r   r   r   r{   S  s    zVertexCover.graphc                 C   s   | j | | S r   r   r)   r   r   r   r   X  s    	zVertexCover.subgraphc                    s    fdd D S )r   c                    s   g | ]} j |qS r   r   r   r3   r   r   r&   k  s     z)VertexCover.subgraphs.<locals>.<listcomp>r   r3   r   r3   r   r   c  s    zVertexCover.subgraphsc                    s   d|krJd| j  krJ|dkr(ddg nddg  fdd	|  D |d< |d
d}|dkrntt| |d
< d|krt d r| |d< nt|d | |d< | j	j
||f||S )a  Plots the cover to the given Cairo context or matplotlib Axes.

        This is done by calling L{Graph.__plot__()} with the same arguments, but
        drawing nice colored blobs around the vertex groups.

        This method understands all the positional and keyword arguments that
        are understood by L{Graph.__plot__()}, only the differences will be
        highlighted here:

          - C{mark_groups}: whether to highlight the vertex clusters by
            colored polygons. Besides the values accepted by L{Graph.__plot__}
            (i.e., a dict mapping colors to vertex indices, a list containing
            lists of vertex indices, or C{False}), the following are also
            accepted:

              - C{True}: all the clusters will be highlighted, the colors matching
                the corresponding color indices from the current palette
                (see the C{palette} keyword argument of L{Graph.__plot__}.

              - A dict mapping cluster indices or tuples of vertex indices to
                color names.  The given clusters or vertex groups will be
                highlighted by the given colors.

              - A list of cluster indices. This is equivalent to passing a
                dict mapping numeric color indices from the current palette
                to cluster indices; therefore, the cluster referred to by element
                I{i} of the list will be highlighted by color I{i} from the
                palette.

            The value of the C{plotting.mark_groups} configuration key is also
            taken into account here; if that configuration key is C{True} and
            C{mark_groups} is not given explicitly, it will automatically be set
            to C{True}.

            In place of lists of vertex indices, you may also use L{VertexSeq}
            instances.

            In place of color names, you may also use color indices into the
            current palette. C{None} as a color name will mean that the
            corresponding group is ignored.

          - C{palette}: the palette used to resolve numeric color indices to RGBA
            values. By default, this is an instance of L{ClusterColoringPalette}.

        @see: L{Graph.__plot__()} for more supported keyword arguments.
        r   r   r   ZdimgreysilverZgrey20Zgrey80c                    s   g | ]} | qS r   r   r   r   r   r   r&     s    z(VertexCover.__plot__.<locals>.<listcomp>r   Nr   r   )r{   r   r   r   r   r   r   r   r   r=   r   )r   r   r   rA   rB   r   r   r   r   r   m  s$    /



 zVertexCover.__plot__c                 #   s`   | j  r<| j jd  | D ]}d fdd|D V  qn | D ]}ddd |D V  q@dS )rg   r   rh   c                 3   s   | ]}t  | V  qd S r   ri   rj   r   r   r   r     s     z:VertexCover._formatted_cluster_iterator.<locals>.<genexpr>c                 s   s   | ]}t |V  qd S r   ri   rj   r   r   r   r     s     Nr   rm   r   r   r   r_     s    
z'VertexCover._formatted_cluster_iterator)N)rn   ro   rp   rq   r!   r   rr   r{   r   r   r   r_   r   r   r   r~   r   r   +  s   	

Hr   c                       sb   e Zd ZdZd fdd	Zdd Zdd Zd	d
 Zdd Zdd Z	dd Z
dd Zdd Z  ZS )CohesiveBlocksa  The cohesive block structure of a graph.

    Instances of this type are created by
    L{Graph.cohesive_blocks()<GraphBase.cohesive_blocks()>}. See the
    documentation of L{Graph.cohesive_blocks()<GraphBase.cohesive_blocks()>}
    for an explanation of what cohesive blocks are.

    This class provides a few more methods that make handling of cohesive
    block structures easier.
    Nc                    sj   |dks|dks|dkr&|  \}}}t || || _|| _t| jD ]\}}|dk rJd| j|< qJdS )au  Constructs a new cohesive block structure for the given graph.

        If any of I{blocks}, I{cohesion} or I{parent} is C{None}, all the
        arguments will be ignored and
        L{Graph.cohesive_blocks()<GraphBase.cohesive_blocks()>} will be called
        to calculate the cohesive blocks. Otherwise, these three variables
        should describe the *result* of a cohesive block structure calculation.
        Chances are that you never have to construct L{CohesiveBlocks}
        instances directly, just use
        L{Graph.cohesive_blocks()<GraphBase.cohesive_blocks()>}.

        @param graph: the graph itself
        @param blocks: a list containing the blocks; each block is described
          as a list containing vertex IDs.
        @param cohesion: the cohesion of each block. The length of this list
          must be equal to the length of I{blocks}.
        @param parent: the parent block of each block. Negative values or
          C{None} mean that there is no parent block for that block. There
          should be only one parent block, which covers the entire graph.
        @see: Graph.cohesive_blocks()
        Nr   )cohesive_blocksrt   r!   	_cohesion_parentr(   )r   r{   blockscohesionparentr%   pr~   r   r   r!     s    zCohesiveBlocks.__init__c                 C   s
   | j | S )z7Returns the cohesion of the group with the given index.r  r)   r   r   r   r    s    zCohesiveBlocks.cohesionc                 C   s   | j dd S )z3Returns the list of cohesion values for each group.Nr	  r3   r   r   r   	cohesions  s    zCohesiveBlocks.cohesionsc                 C   s6   ddl m} dd t| jtt| D }||ddS )a/  Returns a new graph that describes the hierarchical relationships
        between the groups.

        The new graph will be a directed tree; an edge will point from
        vertex M{i} to vertex M{j} if group M{i} is a superset of group M{j}.
        In other words, the edges point downwards.
        r   )Graphc                 S   s   g | ]}|d  dk	r|qS )r   Nr   r   r   r   r   r&      s     z,CohesiveBlocks.hierarchy.<locals>.<listcomp>T)Zdirected)igraphr  zipr  r-   r   )r   r  edgesr   r   r   	hierarchy  s
    zCohesiveBlocks.hierarchyc                 C   s2   d}t | j| jD ]\}}||krt||}q|S )z\Finds the maximum cohesion score among all the groups that contain
        the given vertex.r   )r  r  r   r   )r   r%   r   r  r1   r   r   r   max_cohesion  s
    zCohesiveBlocks.max_cohesionc                 C   sH   dg| j   }t| j| jD ]$\}}|D ]}t|| |||< q*q|S )zvFor each vertex in the graph, returns the maximum cohesion score
        among all the groups that contain the vertex.r   )r=   ru   r  r  r   r   )r   r   r  r1   r%   r   r   r   max_cohesions  s
    zCohesiveBlocks.max_cohesionsc                 C   s
   | j | S )zsReturns the parent group index of the group with the given index
        or C{None} if the given group is the root.r  r)   r   r   r   r    s    zCohesiveBlocks.parentc                 C   s   | j dd S )zjReturns the list of parent group indices for each group or C{None}
        if the given group is the root.Nr  r3   r   r   r   parents  s    zCohesiveBlocks.parentsc                 O   sz   d}d|krt  d r.d}n|d dkr.d}|rPdd t|  D }||d< d|krd|  |d< tj| ||f||S )a-  Plots the cohesive block structure to the given Cairo context or
        matplotlib Axes.

        Since a L{CohesiveBlocks} instance is also a L{VertexCover}, keyword
        arguments accepted by L{VertexCover.__plot__()} are also accepted here.
        The only difference is that the vertices are colored according to their
        maximal cohesions by default, and groups are marked by colored blobs
        except the last group which encapsulates the whole graph.

        See the documentation of L{VertexCover.__plot__()} for more details.
        Fr   r   Tc                 S   s   g | ]}|d  d kr|qS )r   r   r   r   r   r   r&   5  s      z+CohesiveBlocks.__plot__.<locals>.<listcomp>r   )r   r   r(   r
  r  r   r   )r   r   r   rA   rB   Zprepare_groupsr   r   r   r   r   !  s    zCohesiveBlocks.__plot__)NNN)rn   ro   rp   rq   r!   r  r
  r  r  r  r  r  r   r   r   r   r~   r   r    s   !		r  c                    s   | dkrdd t  D nt| tr0|  nt| drt| drz| d }W n tk
rh   d}Y nX |dk	rt|trdd t | D q| q| nt| d	r| ni   fd
d}| S )a  Handles the mark_groups=... keyword argument in plotting methods of
    clusterings.

    This is an internal method, you shouldn't need to mess around with it.
    Its purpose is to handle the extended semantics of the mark_groups=...
    keyword argument in the C{__plot__} method of L{VertexClustering} and
    L{VertexCover} instances, namely the feature that numeric IDs are resolved
    to clusters automatically.
    Tc                 s   s   | ]\}}||fV  qd S r   r   r   r   groupr   r   r   r   L  s     z9_handle_mark_groups_arg_for_clustering.<locals>.<genexpr>r*   r4   r   Nc                 s   s   | ]\}}||fV  qd S r   r   r  r   r   r   r   [  s     r2   c                  3   s.   D ]$\} }t | tr |  } | |fV  qd S r   )
isinstancer   )r  r   
clusteringZ
group_iterr   r   cluster_index_resolverg  s    
zF_handle_mark_groups_arg_for_clustering.<locals>.cluster_index_resolver)r(   r  rz   	iteritemshasattrr   r   )r   r  firstr  r   r  r   r   >  s&    




r   Fc                    s   dd }|| ||  t  t kr2td|rd ksFdkṙ fddtt  D }|  t  }|D ]@}|d8 } |  |   |<  |< | |  |< |< qv |d= |d=  fS )a  Auxiliary method that takes two community structures either as
    membership lists or instances of L{Clustering}, and returns a
    tuple whose two elements are membership lists.

    This is used by L{compare_communities} and L{split_join_distance}.

    @param comm1: the first community structure as a membership list or
      as a L{Clustering} object.
    @param comm2: the second community structure as a membership list or
      as a L{Clustering} object.
    @param remove_none: whether to remove C{None} entries from the membership
      lists. If C{remove_none} is C{False}, a C{None} entry in either C{comm1}
      or C{comm2} will result in an exception. If C{remove_none} is C{True},
      C{None} values are filtered away and only the remaining lists are
      compared.
    c                 S   s   t | tr| jS t| S r   )r  r   r   r   )objr   r   r   _ensure_list  s    
z3_prepare_community_comparison.<locals>._ensure_listz2the two membership vectors must be equal in lengthNc                    s(   g | ] } | d ks | d kr|qS r   r   r   vec1vec2r   r   r&     s      z1_prepare_community_comparison.<locals>.<listcomp>r   )r   rv   r-   reverse)comm1comm2remove_noner  Zidxs_to_removerE   r"   r   r  r   _prepare_community_comparisons  s"    


r&  vic                 C   s(   ddl }t| ||\}}|j|||S )a	  Compares two community structures using various distance measures.

    @param comm1: the first community structure as a membership list or
      as a L{Clustering} object.
    @param comm2: the second community structure as a membership list or
      as a L{Clustering} object.
    @param method: the measure to use. C{"vi"} or C{"meila"} means the
      variation of information metric of Meila (2003), C{"nmi"} or C{"danon"}
      means the normalized mutual information as defined by Danon et al (2005),
      C{"split-join"} means the split-join distance of van Dongen (2000),
      C{"rand"} means the Rand index of Rand (1971), C{"adjusted_rand"}
      means the adjusted Rand index of Hubert and Arabie (1985).
    @param remove_none: whether to remove C{None} entries from the membership
      lists. This is handy if your L{Clustering} object was constructed using
      L{VertexClustering.FromAttribute} using an attribute which was not defined
      for all the vertices. If C{remove_none} is C{False}, a C{None} entry in
      either C{comm1} or C{comm2} will result in an exception. If C{remove_none}
      is C{True}, C{None} values are filtered away and only the remaining lists
      are compared.

    @return: the calculated measure.
    @newfield ref: Reference
    @ref: Meila M: Comparing clusterings by the variation of information.
          In: Scholkopf B, Warmuth MK (eds). Learning Theory and Kernel
          Machines: 16th Annual Conference on Computational Learning Theory
          and 7th Kernel Workship, COLT/Kernel 2003, Washington, DC, USA.
          Lecture Notes in Computer Science, vol. 2777, Springer, 2003.
          ISBN: 978-3-540-40720-1.
    @ref: Danon L, Diaz-Guilera A, Duch J, Arenas A: Comparing community
          structure identification. J Stat Mech P09008, 2005.
    @ref: van Dongen D: Performance criteria for graph clustering and Markov
          cluster experiments. Technical Report INS-R0012, National Research
          Institute for Mathematics and Computer Science in the Netherlands,
          Amsterdam, May 2000.
    @ref: Rand WM: Objective criteria for the evaluation of clustering
          methods. J Am Stat Assoc 66(336):846-850, 1971.
    @ref: Hubert L and Arabie P: Comparing partitions. Journal of
          Classification 2:193-218, 1985.
    r   N)igraph._igraphr&  _igraphZ_compare_communities)r#  r$  methodr%  r  r   r!  r   r   r   r?     s    (r?   c                 C   s&   ddl }t| ||\}}|j||S )a 
  Calculates the split-join distance between two community structures.

    The split-join distance is a distance measure defined on the space of
    partitions of a given set. It is the sum of the projection distance of
    one partition from the other and vice versa, where the projection
    number of A from B is if calculated as follows:

      1. For each set in A, find the set in B with which it has the
         maximal overlap, and take note of the size of the overlap.

      2. Take the sum of the maximal overlap sizes for each set in A.

      3. Subtract the sum from M{n}, the number of elements in the
         partition.

    Note that the projection distance is asymmetric, that's why it has to be
    calculated in both directions and then added together.  This function
    returns the projection distance of C{comm1} from C{comm2} and the
    projection distance of C{comm2} from C{comm1}, and returns them in a pair.
    The actual split-join distance is the sum of the two distances. The reason
    why it is presented this way is that one of the elements being zero then
    implies that one of the partitions is a subpartition of the other (and if
    it is close to zero, then one of the partitions is close to being a
    subpartition of the other).

    @param comm1: the first community structure as a membership list or
      as a L{Clustering} object.
    @param comm2: the second community structure as a membership list or
      as a L{Clustering} object.
    @param remove_none: whether to remove C{None} entries from the membership
      lists. This is handy if your L{Clustering} object was constructed using
      L{VertexClustering.FromAttribute} using an attribute which was not defined
      for all the vertices. If C{remove_none} is C{False}, a C{None} entry in
      either C{comm1} or C{comm2} will result in an exception. If C{remove_none}
      is C{True}, C{None} values are filtered away and only the remaining lists
      are compared.

    @return: the projection distance of C{comm1} from C{comm2} and vice versa
      in a tuple. The split-join distance is the sum of the two.
    @newfield ref: Reference
    @ref: van Dongen D: Performance criteria for graph clustering and Markov
          cluster experiments. Technical Report INS-R0012, National Research
          Institute for Mathematics and Computer Science in the Netherlands,
          Amsterdam, May 2000.

    @see: L{compare_communities()} with C{method = "split-join"} if you are
      not interested in the individual projection distances but only the
      sum of them.
    r   N)r(  r&  r)  Z_split_join_distance)r#  r$  r%  r  r   r!  r   r   r   split_join_distance  s    2r+  c           
      C   s   |rt | d\}}nt | d}g }|rh|  }|D ]0}t }|D ]}|||  qD|t| q6t| |}	|r~|	|fS |	S dS )a%      Calculates the biconnected components of the graph.

    @param return_articulation_points: whether to return the articulation
      points as well
    @return: a L{VertexCover} object describing the biconnected components,
      and optionally the list of articulation points as well
    TFN)r   Zbiconnected_componentsr   r   r   r.   sortedr   )
r{   Zreturn_articulation_pointsZtreesZapsr0   Zedgelisttreer1   Zedge_idr  r   r   r   _biconnected_components  s    	
r.  c                 C   s   t | ft|  S )a  Calculates the cohesive block structure of the graph.

    Cohesive blocking is a method of determining hierarchical subsets of graph
    vertices based on their structural cohesion (i.e. vertex connectivity).
    For a given graph G, a subset of its vertices S is said to be maximally
    k-cohesive if there is no superset of S with vertex connectivity greater
    than or equal to k. Cohesive blocking is a process through which, given a
    k-cohesive set of vertices, maximally l-cohesive subsets are recursively
    identified with l > k. Thus a hierarchy of vertex subsets is obtained in
    the end, with the entire graph G at its root.

    @return: an instance of L{CohesiveBlocks}. See the documentation of
      L{CohesiveBlocks} for more information.
    @see: L{CohesiveBlocks}
    )r  r   r  )r{   r   r   r   _cohesive_blocks#  s    r/  strongc                 C   s   t | t| |S )a  Calculates the (strong or weak) connected components for
    a given graph.

    @param mode: must be either C{"strong"} or C{"weak"}, depending on the
      connected components being sought. Optional, defaults to C{"strong"}.
    @return: a L{VertexClustering} object)rs   r   connected_componentsr{   moder   r   r   _connected_components6  s    r4  c                 C   s   t d | j|dS )z4Deprecated alias to L{Graph.connected_components()}.zHGraph.clusters() is deprecated; use Graph.connected_components() instead)r3  )r   r1  r2  r   r   r   r   @  s    r   N)F)r'  F)F)F)r0  )r0  )'rq   r   r   ior   r(  r   r   Zigraph.configurationr   Zigraph.datatypesr   r   r   Zigraph.drawing.cairo.dendrogramr	   Z$igraph.drawing.matplotlib.dendrogramr
   Zigraph.statisticsr   Zigraph.summaryr   Zigraph.utilsr   r   rs   r   r   r<   r   r  r   r&  r?   r+  r.  r/  r4  r   r   r   r   r   <module>   sB    4  F  
m - }5
+
.
8


