U
    9%e                     @   s  d Z ddl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ZddlmZ dd	lmZmZ d
dddddddgZddhZddddZedZedd4ddZdd Zdd Zd5d d
Zed!d6d"dZG d#d$ d$ejZd%d& ZG d'd dZd7d)dZ d8d*dZ!d9d+dZ"d:d,dZ#d-Z$e$d. Z%e$j&d/dd0e _ e$j&d1dd0e!_ e%j&d/d2d0e"_ e%j&d1d2d0e#_ G d3d dZ'dS );u   
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)	dataclassfield)Enum)
itemgetter)PriorityQueue)py_random_state   )is_arborescenceis_branchingbranching_weightgreedy_branchingmaximum_branchingminimum_branchingmaximum_spanning_arborescenceminimum_spanning_arborescenceArborescenceIteratorEdmondsmaxmin	branchingarborescence)r   r   spanning arborescenceinf   c                    s   d  fddt| D S )N c                    s   g | ]}  tjqS  )choicestringascii_letters).0nseedr   b/var/www/html/Darija-Ai-API/env/lib/python3.8/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_weightC   s    r,   c                 C   s   | S r)   r   r*   r   r   r#   _max_weightG   s    r-   r+   c                    s    t  fdd| jddD S )a  
    Returns the total weight of a branching.

    You must access this function through the networkx.algorithms.tree module.

    Parameters
    ----------
    G : DiGraph
        The directed graph.
    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.

    Returns
    -------
    weight: int or float
        The total weight of the branching.

    Examples
    --------
    >>> G = nx.DiGraph()
    >>> G.add_weighted_edges_from([(0, 1, 2), (1, 2, 4), (2, 3, 3), (3, 4, 2)])
    >>> nx.tree.branching_weight(G)
    11

    c                 3   s   | ]}|d    V  qdS )   Nget)r   edgeattrdefaultr   r#   	<genexpr>i   s     z#branching_weight.<locals>.<genexpr>Tdata)sumedges)Gr3   r4   r   r2   r#   r   K   s       c                    s$  |t krtd|dkr d}nd} dkr6t|d  fdd| jdd	D }z|jtd
dd|d W n& tk
r   |jtd
|d Y nX t }|	|  tj
 }t|D ]f\}	\}
}}||
 || krqq||dkrqqi } dk	r|| < |j|
|f| ||
| q|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.

    Unknown value for `kind`.r   FTNr!   c                    s$   g | ]\}}}|||  fqS r   r/   )r   uvr7   r2   r   r#   r$      s     z$greedy_branching.<locals>.<listcomp>r6   r.   r   r   )keyreverse)KINDSnxNetworkXExceptionr(   r9   sortr   	TypeErrorZDiGraphadd_nodes_fromutils	UnionFind	enumerate	in_degreeadd_edgeunion)r:   r3   r4   kindr"   r@   r9   Bufir=   r>   wr7   r   r2   r#   r   l   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)selfrS   r3   cls	__class__r   r#   rU      s    zMultiDiGraph_EdgeKey.__init__c                 C   sd   t  }| j|  D ]}|| q| j|  D ]}|| q2|D ]}| j|= qF| j| d S r)   )setpredvaluesupdatesuccrW   rV   remove_node)rX   r    keysZkeydictr?   r   r   r#   ra      s    
z MultiDiGraph_EdgeKey.remove_nodec                 C   s   |D ]}|  | qd S r)   )ra   )rX   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)rW   	ExceptionrV   rK   r`   )rX   Z
u_for_edgeZ
v_for_edgeZkey_for_edger3   r=   r>   r?   uuvv_r   r   r#   rK      s    
zMultiDiGraph_EdgeKey.add_edgec                 K   s(   |D ]\}}}}| j |||f| qd S r)   )rK   )rX   Zebunch_to_addr3   r=   r>   kdr   r   r#   add_edges_from   s    z#MultiDiGraph_EdgeKey.add_edges_fromc              
   C   sd   z| j | \}}}W n2 tk
rF } ztd||W 5 d }~X Y nX | j |= | j||| d S )NzInvalid edge key )rW   KeyErrorrV   Zremove_edge)rX   r?   r=   r>   rh   errr   r   r#   remove_edge_with_key   s    "z)MultiDiGraph_EdgeKey.remove_edge_with_keyc                 C   s   t d S r)   )NotImplementedError)rX   Zebunchr   r   r#   remove_edges_from   s    z&MultiDiGraph_EdgeKey.remove_edges_from)N)__name__
__module____qualname____doc__rU   ra   rd   rK   rk   rn   rp   __classcell__r   r   rZ   r#   rR      s   	rR   c                    sB   t  || 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$    |   |   }t|}|d S )Nr   )rb   list)rP   rg   rb   )r:   nodesr   r#   	first_key  s    zget_path.<locals>.first_keyc                    s   g | ]\}} ||qS r   r   )r   rP   rg   )rx   r   r#   r$     s     zget_path.<locals>.<listcomp>r   N)rB   Zshortest_pathrI   )r:   r=   r>   r9   r   )r:   rx   rw   r#   get_path  s    ry   c                   @   s,   e Zd ZdZdddZdd ZdddZdS )r   a  
    Edmonds algorithm [1]_ for finding optimal branchings and spanning
    arborescences.

    This algorithm can find both minimum and maximum spanning arborescences and
    branchings.

    Notes
    -----
    While this algorithm can find a minimum branching, since it isn't required
    to be spanning, the minimum branching is always from the set of negative
    weight edges which is most likely the empty set for most graphs.

    References
    ----------
    .. [1] J. Edmonds, Optimum Branchings, Journal of Research of the National
           Bureau of Standards, 1967, Vol. 71B, p.233-240,
           https://archive.org/details/jresv71Bn4p233

    Nc                 C   s&   || _ d| _g | _t|dd | _d S )NTr!   z_{0})
G_originalstorer9   r(   template)rX   r:   r"   r   r   r#   rU   1  s    zEdmonds.__init__c                 C   sD  |t krtd|| _|| _|| _|| _|dkr>t | _}n
t	 | _}|d krZt
|d}|| _dt
|d | _t  | _}	t| jjddD ]v\}
\}}}|||||i}||d k	r||||< |r| D ]\}}||kr|||< q|	j|||
f| qd| _t | _i | j_g | _g | _tj | _g | _g | _d S )Nr<   r   r!   Z
candidate_Tr6   r   )rA   rB   rC   r3   r4   rM   styler,   transr-   r(   _attrcandidate_attrrR   r:   rI   rz   r9   r0   itemsrK   levelrN   rW   graphs
branchingsrG   rH   rO   circuitsminedge_circuit)rX   r3   r4   rM   r}   preserve_attrsr"   	partitionr~   r:   r?   r=   r>   r7   rj   Zd_kZd_vr   r   r#   _init>  s>    


 
	zEdmonds._initr+   r   r   r   Fc           )   	      s  |  ||||| | j}| j| j  }	t }
tt  }| j j	} fdd}zt
|}W n tk
r   t t|	kstt|	rt|	st| jr| j   | j|	  | jg  | jd Y qY nX ||
krq\|
| |	| ||\}}|dkr"q\q\|d }|| || kr\t|	||\}}||d  nd\}}| jdkr|dkrd}nd	}|r\|i}|d
 dk	r|d
 |< |	j|||d f| d	 | | |d  | j< ||| |dk	r\t}d}i }|D ]P}|	j| \}}}| }|||< |t j!j"krFq
||k r
|}|}q
| j| | j| | jr| j   | j|	  | j#$| j%} | g } j&d	d	dD ]\}}}}||kr||krqn| }|||||f nJ||kr| }||||  7 }| }||< |||||f nqƐqƈ '| |	'| |
(t| |D ]R\}}}} j|||f| | j|kr||| j= |	j|||f| ||| q|tt  }|  j%d7  _%q\| j)* }dd } t| j| j% j}!| j%dkr|  j%d8  _%| j#$| j%}"| j| j% }#| | j| j%d  |"|!\}$}%|!+|# |$r| j| j% }|dkrt,|!-| nX| j| j%   j|% d }&|#D ]&}% j|% \}}}||&kr qqt,d|!-|% q|!| _&|.| j) |!D ]v}%| jd j|% \}}}'| j/| 0|'| j/ i}|rp|'1 D ]$\}}(|| j/| jfkrJ|(||< qJ|j||f| q|S )a9  
        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`)
        partition : str
            The edge attribute holding edge partition data. Used in the
            spanning arborescence iterator.
        seed : integer, random_state, or None (default)
            Indicator of random number generation state.
            See :ref:`Randomness<randomness>`.

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

        c                    s   d}t  } j| dddD ]r\}}}}|tjjkr:q| }|tjjkrr|}|| |||f}||f  S ||kr|}|| |||f}q||fS )aQ  
            Find the edge directed toward v with maximal weight.

            If an edge partition exists in this graph, return the included edge
            if it exists and no not return any excluded edges. There can only
            be one included edge for each vertex otherwise the edge partition is
            empty.
            NTr7   rb   )INFin_edgesr0   rB   EdgePartitionEXCLUDEDINCLUDED)r>   r1   r+   r=   rh   r?   r7   Z
new_weightr:   r3   r   r   r#   desired_edge  s    	z*Edmonds.find_optimum.<locals>.desired_edgeNr   r.   )NNr   FTr;   r   r   c                 S   sV   || krt |d| j| D ]0}| j| | D ]}||kr2d|f    S q2q 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 GF)TNN)re   r]   )r:   r=   Zedgekeysr>   edgekeyr   r   r#   is_rootl  s    z%Edmonds.find_optimum.<locals>.is_rootz+Couldn't find edge incoming to merged node.)2r   rO   r:   rN   r\   iterrv   rw   r   r]   nextStopIterationlenAssertionErrorr
   r{   r   appendcopyr   r   r   addadd_nodery   r}   r0   rK   r   rL   r   rW   rB   r   r   r|   formatr   r9   rd   difference_updaterz   r[   r_   re   removerF   r3   r~   r   ))rX   r3   r4   rM   r}   r   r   r"   rO   rN   Drw   ZG_predr   r>   r1   r+   r=   ZQ_nodesZQ_edgesZ
acceptableddZ	minweightZminedgeZQ_incoming_weightZedge_keyr7   rQ   new_nodeZ	new_edgesr?   Hr   r9   Zmerged_nodeZcircuitZisrootr   targetrj   valuer   r   r#   find_optimum  s    ,
















zEdmonds.find_optimum)N)r+   r   r   r   FNN)rq   rr   rs   rt   rU   r   r   r   r   r   r#   r     s   
G       Fc                 C   s"   t | }|j||dd||d}|S )Nr   r   rM   r}   r   r   r   r   r:   r3   r4   r   r   edrN   r   r   r#   r     s    c                 C   s"   t | }|j||dd||d}|S )Nr   r   r   r   r   r   r   r#   r     s    c                 C   s:   t | }|j||dd||d}t|s6d}tj||S )Nr   r   r   z&No maximum spanning arborescence in G.r   r   r	   rB   	exceptionrC   r:   r3   r4   r   r   r   rN   msgr   r   r#   r     s    c                 C   s:   t | }|j||dd||d}t|s6d}tj||S )Nr   r   r   z&No minimum spanning arborescence in G.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`)
partition : str
    The key for the edge attribute containing the partition
    data on the graph. Edges can be included, excluded or open using the
    `EdgePartition` enum.

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

maximum)rM   r}   minimumr   c                   @   sZ   e Zd ZdZeddG dd dZddd	Zd
d Zdd Zdd Z	dd Z
dd ZdS )r   u  
    Iterate over all spanning arborescences of a graph in either increasing or
    decreasing cost.

    Notes
    -----
    This iterator uses the partition scheme from [1]_ (included edges,
    excluded edges and open edges). It generates minimum spanning
    arborescences using a modified Edmonds' Algorithm which respects the
    partition of edges. For arborescences with the same weight, ties are
    broken arbitrarily.

    References
    ----------
    .. [1] G.K. Janssens, K. Sörensen, An algorithm to generate all spanning
           trees in order of increasing cost, Pesquisa Operacional, 2005-08,
           Vol. 25 (2), p. 219-229,
           https://www.scielo.br/j/pope/a/XHswBwRwJyrfL88dmMwYNWp/?lang=en
    T)orderc                   @   s4   e Zd ZU dZeed< eddZeed< dd Z	dS )	zArborescenceIterator.Partitionz
        This dataclass represents a partition and stores a dict with the edge
        data and the weight of the minimum spanning arborescence of the
        partition dict.
        
mst_weightF)comparepartition_dictc                 C   s   t | j| j S r)   )r   	Partitionr   r   r   )rX   r   r   r#   __copy___  s     z'ArborescenceIterator.Partition.__copy__N)
rq   rr   rs   rt   float__annotations__r   r   dictr   r   r   r   r#   r   T  s   
r   r+   Nc                 C   s   |  | _|| _|| _|rtnt| _d| _|dk	rzi }|d D ]}tj	j
||< q>|d D ]}tj	j||< qXtd|| _nd| _dS )a  
        Initialize the iterator

        Parameters
        ----------
        G : nx.DiGraph
            The directed graph which we need to iterate trees over

        weight : String, default = "weight"
            The edge attribute used to store the weight of the edge

        minimum : bool, default = True
            Return the trees in increasing order while true and decreasing order
            while false.

        init_partition : tuple, default = None
            In the case that certain edges have to be included or excluded from
            the arborescences, `init_partition` should be in the form
            `(included_edges, excluded_edges)` where each edges is a
            `(u, v)`-tuple inside an iterable such as a list or set.

        z;ArborescenceIterators super secret partition attribute nameNr   r   )r   r:   r+   r   r   r   methodpartition_keyrB   r   r   r   r   r   init_partition)rX   r:   r+   r   r   r   er   r   r#   rU   d  s    

zArborescenceIterator.__init__c                 C   s   t  | _| | j | jdk	r*| | j | j| j| j| jddj	| jd}| j
| | jr`|n| | jdkrri n| jj | S )zu
        Returns
        -------
        ArborescenceIterator
            The iterator object for this graph
        NTr   r   r*   )r   partition_queue_clear_partitionr:   r   _write_partitionr   r+   r   sizeputr   r   r   )rX   r   r   r   r#   __iter__  s*    
	zArborescenceIterator.__iter__c                 C   s\   | j  r| `| ` t| j  }| | | j| j| j| jdd}| 	|| | 
| |S )z
        Returns
        -------
        (multi)Graph
            The spanning tree of next greatest weight, which ties broken
            arbitrarily.
        Tr   )r   emptyr:   r   r0   r   r   r+   r   
_partitionr   )rX   r   Znext_arborescencer   r   r#   __next__  s    



zArborescenceIterator.__next__c              	   C   s   |  d|j }|  d|j }|jD ]}||jkr*tjj|j|< tjj|j|< | | zL| j	| j
| j| jdd}|j| jd}| jr|n| |_| j|  W n tjk
r   Y nX |j |_q*dS )a  
        Create new partitions based of the minimum spanning tree of the
        current minimum partition.

        Parameters
        ----------
        partition : Partition
            The Partition instance used to generate the current minimum spanning
            tree.
        partition_arborescence : nx.Graph
            The minimum spanning arborescence of the input partition.
        r   Tr   r*   N)r   r   r   r9   rB   r   r   r   r   r   r:   r+   r   r   r   r   r   r   r   rC   )rX   r   Zpartition_arborescencep1p2r   Zp1_mstZp1_mst_weightr   r   r#   r     s(    


zArborescenceIterator._partitionc                 C   s  | j jddD ]<\}}}||f|jkr<|j||f || j< qtjj|| j< q| j D ]}d}d}| j j|ddD ]D\}}}|| jtjj	kr|d7 }qn|| jtjj
krn|d7 }qn|dkrR|| j |d krR| j j|ddD ],\}}}|| jtjj	krtjj
|| j< qqRdS )a  
        Writes the desired partition into the graph to calculate the minimum
        spanning tree. Also, if one incoming edge is included, mark all others
        as excluded so that if that vertex is merged during Edmonds' algorithm
        we cannot still pick another of that vertex's included edges.

        Parameters
        ----------
        partition : Partition
            A Partition dataclass describing a partition on the edges of the
            graph.
        Tr6   r   )rc   r7   r   N)r:   r9   r   r   rB   r   ZOPENr   r0   r   r   rJ   )rX   r   r=   r>   rj   r    Zincluded_countZexcluded_countr   r   r#   r     s     


z%ArborescenceIterator._write_partitionc                 C   s.   |j ddD ]\}}}| j|kr|| j= qdS )z7
        Removes partition data from the graph
        Tr6   N)r9   r   )rX   r:   r=   r>   rj   r   r   r#   r     s    
z%ArborescenceIterator._clear_partition)r+   TN)rq   rr   rs   rt   r   r   rU   r   r   r   r   r   r   r   r   r#   r   ?  s   
+ (")r   N)r+   r   )r+   r   r   N)r+   r   FN)r+   r   FN)r+   r   FN)r+   r   FN)(rt   r   dataclassesr   r   enumr   operatorr   queuer   ZnetworkxrB   Znetworkx.utilsr   Zrecognitionr	   r
   __all__rA   ZSTYLESr   r   r(   r,   r-   r   r   ZMultiDiGraphrR   ry   r   r   r   r   r   Zdocstring_branchingZdocstring_arborescencer   r   r   r   r   r#   <module>   s   
!OG   0       
       
       
       
    