3
Mdsa                 @   sH  d Z ddlZddlmZ ddlZddlmZ ddlm	Z	m
Z
 ddd	d
dddgZddhZddddZedZedd/ddZdd Zdd Zd0ddZedd1ddZG dd  d ejZd!d" ZG d#d dZd2d%d	Zd3d&d
Zd4d'dZd5d(dZd)Zed* Zejd+dd,e_ ejd-dd,e_ ejd+d.d,e_ ejd-d.d,e_ dS )6u   
Algorithms for finding optimum branchings and spanning arborescences.

This implementation is based on:

    J. Edmonds, Optimum branchings, J. Res. Natl. Bur. Standards 71B (1967),
    233–240. URL: http://archive.org/details/jresv71Bn4p233

    N)
itemgetter)py_random_state   )is_arborescenceis_branchingbranching_weightgreedy_branchingmaximum_branchingminimum_branchingmaximum_spanning_arborescenceminimum_spanning_arborescenceEdmondsmaxmin	branchingarborescence)r   r   zspanning arborescenceinf   c                s   dj  fddt| D S )N c                s   g | ]} j tjqS  )choicestringascii_letters).0n)seedr   U/var/www/html/virt/lib/python3.6/site-packages/networkx/algorithms/tree/branchings.py
<listcomp>?   s    z!random_string.<locals>.<listcomp>)joinrange)Lr   r   )r   r   random_string=   s    r!   c             C   s   |  S )Nr   )weightr   r   r   _min_weightB   s    r#   c             C   s   | S )Nr   )r"   r   r   r   _max_weightF   s    r$   r"   c                s    t  fdd| jddD S )z3
    Returns the total weight of a branching.

    c             3   s   | ]}|d  j  V  qdS )   N)get)r   edge)attrdefaultr   r   	<genexpr>O   s    z#branching_weight.<locals>.<genexpr>T)data)sumedges)Gr(   r)   r   )r(   r)   r   r   J   s       c                s(  |t krtjd|dkr d}nd} dkr6t|d  fdd| jdd	D }y|jtd
dd|d W n& tk
r   |jtd
|d Y nX tj }|j	|  tj
j }xrt|D ]f\}	\}
}}||
 || krqq|j|dkrqqi } dk	r|| < |j|
|f| |j|
| qW |S )a7  
    Returns a branching obtained through a greedy algorithm.

    This algorithm is wrong, and cannot give a proper optimal branching.
    However, we include it for pedagogical reasons, as it can be helpful to
    see what its outputs are.

    The output is a branching, and possibly, a spanning arborescence. However,
    it is not guaranteed to be optimal in either case.

    Parameters
    ----------
    G : DiGraph
        The directed graph to scan.
    attr : str
        The attribute to use as weights. If None, then each edge will be
        treated equally with a weight of 1.
    default : float
        When `attr` is not None, then if an edge does not have that attribute,
        `default` specifies what value it should take.
    kind : str
        The type of optimum to search for: 'min' or 'max' greedy branching.
    seed : integer, random_state, or None (default)
        Indicator of random number generation state.
        See :ref:`Randomness<randomness>`.

    Returns
    -------
    B : directed graph
        The greedily obtained branching.

    zUnknown value for `kind`.r   FTN)r   c                s$   g | ]\}}}|||j  fqS r   )r&   )r   uvr+   )r(   r)   r   r   r      s    z$greedy_branching.<locals>.<listcomp>)r+   r%   r   r   )keyreverse)KINDSnxNetworkXExceptionr!   r-   sortr   	TypeErrorZDiGraphadd_nodes_fromutils	UnionFind	enumerateZ	in_degreeadd_edgeunion)r.   r(   r)   kindr   r3   r-   Bufir0   r1   wr+   r   )r(   r)   r   r   R   s4    "




c                   sR   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
  ZS )MultiDiGraph_EdgeKeya  
    MultiDiGraph which assigns unique keys to every edge.

    Adds a dictionary edge_index which maps edge keys to (u, v, data) tuples.

    This is not a complete implementation. For Edmonds algorithm, we only use
    add_node and add_edge, so that is all that is implemented here. During
    additions, any specified keys are ignored---this means that you also
    cannot update edge attributes through add_node and add_edge.

    Why do we need this? Edmonds algorithm requires that we track edges, even
    as we change the head and tail of an edge, and even changing the weight
    of edges. We must reliably track edges across graph mutations.

    Nc                s*   t  }|jf d|i| || _i | _d S )Nincoming_graph_data)super__init___cls
edge_index)selfrE   r(   cls)	__class__r   r   rG      s    zMultiDiGraph_EdgeKey.__init__c             C   sp   t  }x | j| j D ]}|j| qW x | j| j D ]}|j| q8W x|D ]}| j|= qPW | jj| d S )N)setpredvaluesupdatesuccrI   rH   remove_node)rJ   r   keysZkeydictr2   r   r   r   rR      s    
z MultiDiGraph_EdgeKey.remove_nodec             C   s   x|D ]}| j | qW d S )N)rR   )rJ   Znbunchr   r   r   r   remove_nodes_from   s    
z&MultiDiGraph_EdgeKey.remove_nodes_fromc             K   s   |||  }}}|| j krJ| j | \}}	}
||ks:||	krJtd|d| jj|||f| ||| j| | | f| j |< dS )z'
        Key is now required.

        zKey z is already in use.N)rI   	ExceptionrH   r=   rQ   )rJ   Z
u_for_edgeZ
v_for_edgeZkey_for_edger(   r0   r1   r2   uuvv_r   r   r   r=      s    
zMultiDiGraph_EdgeKey.add_edgec             K   s,   x&|D ]\}}}}| j |||f| qW d S )N)r=   )rJ   Zebunch_to_addr(   r0   r1   kdr   r   r   add_edges_from   s    z#MultiDiGraph_EdgeKey.add_edges_fromc             C   sd   y| j | \}}}W n2 tk
rF } ztd||W Y d d }~X nX | j |= | jj||| d S )NzInvalid edge key )rI   KeyErrorrH   Zremove_edge)rJ   r2   r0   r1   rX   er   r   r   remove_edge_with_key   s    "z)MultiDiGraph_EdgeKey.remove_edge_with_keyc             C   s   t d S )N)NotImplementedError)rJ   Zebunchr   r   r   remove_edges_from   s    z&MultiDiGraph_EdgeKey.remove_edges_from)N)__name__
__module____qualname____doc__rG   rR   rT   r=   r[   r^   r`   __classcell__r   r   )rL   r   rD      s   	rD   c                sB   t j || fddfddtdd D }|fS )z
    Returns the edge keys of the unique path between u and v.

    This is not a generic function. G must be a branching and an instance of
    MultiDiGraph_EdgeKey.

    c                s$    |   | j  }t|}|d S )Nr   )rS   list)rB   rW   rS   )r.   nodesr   r   	first_key   s    zget_path.<locals>.first_keyc                s   g | ]\}} ||qS r   r   )r   rB   rW   )rh   r   r   r      s    zget_path.<locals>.<listcomp>r   N)r5   Zshortest_pathr<   )r.   r0   r1   r-   r   )r.   rh   rg   r   get_path   s    ri   c               @   s,   e Zd ZdZdddZdd ZdddZdS )r   zW
    Edmonds algorithm for finding optimal branchings and spanning arborescences.

    Nc             C   s&   || _ d| _g | _t|dd | _d S )NT)r   z_{0})
G_originalstorer-   r!   template)rJ   r.   r   r   r   r   rG     s    zEdmonds.__init__c             C   s0  |t krtjd|| _|| _|| _|| _|dkr>t | _}n
t	 | _}|d krZt
|d}|| _dt
|d | _t  | _}xtt| jjddD ]^\}	\}
}}|||j||i}|rx$|j D ]\}}||kr|||< qW |j|
||	f| qW d| _t | _i | j_g | _g | _tjj | _g | _g | _d S )NzUnknown value for `kind`.r   )r   Z
candidate_T)r+   r   )r4   r5   r6   r(   r)   r?   styler#   transr$   r!   _attrcandidate_attrrD   r.   r<   rj   r-   r&   itemsr=   levelr@   rI   graphs
branchingsr:   r;   rA   circuitsminedge_circuit)rJ   r(   r)   r?   rm   preserve_attrsr   rn   r.   r2   r0   r1   r+   rZ   Zd_kZd_vr   r   r   _init  s:    


"	zEdmonds._initr"   r   r   r   Fc       (         s`  | j ||||| | j}| j| j  }t }	tt j }
| j j	} fdd}x`yt
|
}W n| tk
r   t t|kstt|rt|st| jr| jj j  | jj|j  | jjg  | jjd P Y nX ||	krq\|	j| |j| ||\}}|dkrq\q\|d }|| || krXt|||\}}|j|d  nd\}}| jdkr||dkr|d}nd}|r\|i}|j|||d f| d | | |d  | j< |j|| |dk	r\t}d}i }x@|D ]8}|j| \}}}| }|||< ||k r|}|}qW | jj| | jj| | jrN| jj j  | jj|j  | jj | j!} j| g }x j"ddd	D ]\}}}}||kr||krqn|j }|j||||f nJ||kr| }||||  7 }|j }||< |j||||f nqqW  j#| |j#| |	j$t| xZ|D ]R\}}}} j|||f| | j|krD|| j= |j|||f| |j|| qDW tt j }
|  j!d
7  _!q\W | j%j& }dd }t| j| j! j} x| j!dkr|  j!d
8  _!| jj | j!}!| j| j! }"|| j| j!d
  |!| \}#}$| j'|" |#rh| j| j! }|dkr\t(| j)| nX| j| j!   j|$ d
 }%x2|"D ]"}$ j|$ \}}}||%krP qW t(d| j)|$ qW | | _"|j*| j% x| D ]z}$| jd j|$ \}}}&| j+| j,|&| j+ i}|rFx0|&j- D ]$\}}'|| j+| jgkr|'||< qW |j||f| qW |S )a  
        Returns a branching from G.

        Parameters
        ----------
        attr : str
            The edge attribute used to in determining optimality.
        default : float
            The value of the edge attribute used if an edge does not have
            the attribute `attr`.
        kind : {'min', 'max'}
            The type of optimum to search for, either 'min' or 'max'.
        style : {'branching', 'arborescence'}
            If 'branching', then an optimal branching is found. If `style` is
            'arborescence', then a branching is found, such that if the
            branching is also an arborescence, then the branching is an
            optimal spanning arborescences. A given graph G need not have
            an optimal spanning arborescence.
        preserve_attrs : bool
            If True, preserve the other edge attributes of the original
            graph (that are not the one passed to `attr`)
        seed : integer, random_state, or None (default)
            Indicator of random number generation state.
            See :ref:`Randomness<randomness>`.

        Returns
        -------
        H : (multi)digraph
            The branching.

        c                sT   d}t  }x@ j| dddD ],\}}}}| }||kr|}|| ||f}qW ||fS )zO
            Find the edge directed toward v with maximal weight.

            NT)r+   rS   )INFZin_edges)r1   r'   r"   r0   rX   r2   r+   Z
new_weight)r.   r(   r   r   desired_edge  s    z*Edmonds.find_optimum.<locals>.desired_edgeNr   r%   r   FT)r+   rS   r   c             S   sZ   || krt |dx>| j| D ],}x&| j| | D ]}||kr6d|fS q6W q"W dS dS )z
            Returns True if `u` is a root node in G.

            Node `u` will be a root node if its in-degree, restricted to the
            specified edges, is equal to 0.

            z	 not in GFTN)TN)rU   rN   )r.   r0   Zedgekeysr1   edgekeyr   r   r   is_root&  s    z%Edmonds.find_optimum.<locals>.is_rootz+Couldn't find edge incoming to merged node.)NN).rx   rA   r.   r@   rM   iterrf   rg   ro   rN   nextStopIterationlenAssertionErrorr   rk   rs   appendcopyrt   ru   rv   addadd_noderi   rm   r=   rp   r>   ry   rI   rl   formatrr   r-   rT   difference_updaterj   rL   rP   rU   remover9   r(   rn   rq   )(rJ   r(   r)   r?   rm   rw   r   rA   r@   Drg   ZG_predrz   r1   r'   r"   r0   ZQ_nodesZQ_edgesZ
acceptableddZ	minweightZminedgeZQ_incoming_weightZedge_keyr+   rC   new_nodeZ	new_edgesr2   Hr|   r-   Zmerged_nodeZcircuitZisrootr{   targetrZ   valuer   )r.   r(   r   find_optimumT  s    (




















zEdmonds.find_optimum)N)r"   r   r   r   FN)ra   rb   rc   rd   rG   rx   r   r   r   r   r   r      s   
C     Fc             C   s    t | }|j||dd|d}|S )Nr   r   )r?   rm   rw   )r   r   )r.   r(   r)   rw   edr@   r   r   r   r	     s    c             C   s    t | }|j||dd|d}|S )Nr   r   )r?   rm   rw   )r   r   )r.   r(   r)   rw   r   r@   r   r   r   r
     s    c             C   s8   t | }|j||dd|d}t|s4d}tjj||S )Nr   r   )r?   rm   rw   z&No maximum spanning arborescence in G.)r   r   r   r5   	exceptionr6   )r.   r(   r)   rw   r   r@   msgr   r   r   r     s    c             C   s8   t | }|j||dd|d}t|s4d}tjj||S )Nr   r   )r?   rm   rw   z&No minimum spanning arborescence in G.)r   r   r   r5   r   r6   )r.   r(   r)   rw   r   r@   r   r   r   r   r     s    a  
Returns a {kind} {style} from G.

Parameters
----------
G : (multi)digraph-like
    The graph to be searched.
attr : str
    The edge attribute used to in determining optimality.
default : float
    The value of the edge attribute used if an edge does not have
    the attribute `attr`.
preserve_attrs : bool
    If True, preserve the other attributes of the original graph (that are not
    passed to `attr`)

Returns
-------
B : (multi)digraph-like
    A {kind} {style}.
zV
Raises
------
NetworkXException
    If the graph does not contain a {kind} {style}.

maximum)r?   rm   Zminimumzspanning arborescence)r   N)r"   r   )r"   r   r   N)r"   r   F)r"   r   F)r"   r   F)r"   r   F) rd   r   operatorr   Znetworkxr5   Znetworkx.utilsr   Zrecognitionr   r   __all__r4   STYLESfloatry   r!   r#   r$   r   r   ZMultiDiGraphrD   ri   r   r	   r
   r   r   Zdocstring_branchingZdocstring_arborescencer   r   r   r   r   <module>	   sZ   
OG   



