U
    :vf8                     @   s   d Z ddlZddlZddlZddlmZmZ ddlmZm	Z	m
Z
 ddlmZmZ ddlZdddd	d
dddddddgZd#ddZdd Zd$ddZd%ddZd&ddZdd	 Zd'dd
Zdd Zd(ddZG dd dZd)ddZd d Zd!d Zd"d ZdS )*a  
Miscellaneous Helpers for NetworkX.

These are not imported into the base networkx namespace but
can be accessed, for example, as

>>> import networkx
>>> networkx.utils.make_list_of_ints({1, 2, 3})
[1, 2, 3]
>>> networkx.utils.arbitrary_element({5, 1, 7})  # doctest: +SKIP
1
    N)defaultdictdeque)IterableIteratorSized)chainteeflattenmake_list_of_intsdict_to_numpy_arrayarbitrary_elementpairwisegroupscreate_random_statecreate_py_random_statePythonRandomInterfacenodes_equaledges_equalgraphs_equalc                 C   sh   t | ttfrt | tr| S |dkr(g }| D ]2}t |ttfrHt |trT|| q,t|| q,t|S )z>Return flattened version of (possibly nested) iterable object.N)
isinstancer   r   strappendr	   tuple)objresultitem r   7/tmp/pip-unpacked-wheel-_lngutwb/networkx/utils/misc.pyr	   ,   s    c              	   C   s   t | tspg }| D ]X}d| }zt|}W n  tk
rL   t|dY nX ||kr`t||| q|S t| D ]f\}}d| }t |trqxzt|}W n  tk
r   t|dY nX ||krt||| |< qx| S )a*  Return list of ints from sequence of integral numbers.

    All elements of the sequence must satisfy int(element) == element
    or a ValueError is raised. Sequence is iterated through once.

    If sequence is a list, the non-int values are replaced with ints.
    So, no new list is created
    zsequence is not all integers: N)r   listint
ValueErrornxZNetworkXErrorr   	enumerate)sequencer   ierrmsgiiZindxr   r   r   r
   :   s0    	






c              	   C   s4   zt | |W S  ttfk
r.   t| | Y S X dS )zPConvert a dictionary of dictionaries to a numpy array
    with optional mapping.N)_dict_to_numpy_array2AttributeError	TypeError_dict_to_numpy_array1)dmappingr   r   r   r   ^   s    c              
   C   s   ddl }|dkrRt|  }|  D ]\}}||  q$tt|tt|}t|}|	||f}| D ]H\}}	| D ]6\}
}z| | |
 ||	|f< W q t
k
r   Y qX qqp|S )zYConvert a dictionary of dictionaries to a 2d numpy array
    with optional mapping.

    r   N)numpysetkeysitemsupdatedictziprangelenzerosKeyError)r+   r,   npskvnak1r$   Zk2jr   r   r   r'   i   s    
r'   c                 C   sn   ddl }|dkr2t|  }tt|tt|}t|}||}| D ]\}}|| }| | ||< qL|S )zJConvert a dictionary of numbers to a 1d numpy array with optional mapping.r   N)	r-   r.   r/   r2   r3   r4   r5   r6   r0   )r+   r,   r8   r9   r<   r=   r>   r$   r   r   r   r*      s    
r*   c                 C   s   t | trtdtt| S )a  Returns an arbitrary element of `iterable` without removing it.

    This is most useful for "peeking" at an arbitrary element of a set,
    but can be used for any list, dictionary, etc., as well.

    Parameters
    ----------
    iterable : `abc.collections.Iterable` instance
        Any object that implements ``__iter__``, e.g. set, dict, list, tuple,
        etc.

    Returns
    -------
    The object that results from ``next(iter(iterable))``

    Raises
    ------
    ValueError
        If `iterable` is an iterator (because the current implementation of
        this function would consume an element from the iterator).

    Examples
    --------
    Arbitrary elements from common Iterable objects:

    >>> nx.utils.arbitrary_element([1, 2, 3])  # list
    1
    >>> nx.utils.arbitrary_element((1, 2, 3))  # tuple
    1
    >>> nx.utils.arbitrary_element({1, 2, 3})  # set
    1
    >>> d = {k: v for k, v in zip([1, 2, 3], [3, 2, 1])}
    >>> nx.utils.arbitrary_element(d)  # dict_keys
    1
    >>> nx.utils.arbitrary_element(d.values())   # dict values
    3

    `str` is also an Iterable:

    >>> nx.utils.arbitrary_element("hello")
    'h'

    :exc:`ValueError` is raised if `iterable` is an iterator:

    >>> iterator = iter([1, 2, 3])  # Iterator, *not* Iterable
    >>> nx.utils.arbitrary_element(iterator)
    Traceback (most recent call last):
        ...
    ValueError: cannot return an arbitrary item from an iterator

    Notes
    -----
    This function does not return a *random* element. If `iterable` is
    ordered, sequential calls will return the same value::

        >>> l = [1, 2, 3]
        >>> nx.utils.arbitrary_element(l)
        1
        >>> nx.utils.arbitrary_element(l)
        1

    z0cannot return an arbitrary item from an iterator)r   r   r    nextiter)iterabler   r   r   r      s    ?
Fc                 C   s:   t | \}}t|d}|dkr0t|t||fS t||S )z&s -> (s0, s1), (s1, s2), (s2, s3), ...NT)r   r@   r3   r   )rB   Zcyclicr=   bfirstr   r   r   r      s
    
c                 C   s0   t t}|  D ]\}}|| | qt|S )a  Converts a many-to-one mapping into a one-to-many mapping.

    `many_to_one` must be a dictionary whose keys and values are all
    :term:`hashable`.

    The return value is a dictionary mapping values from `many_to_one`
    to sets of keys from `many_to_one` that have that value.

    Examples
    --------
    >>> from networkx.utils import groups
    >>> many_to_one = {"a": 1, "b": 1, "c": 2, "d": 3, "e": 3}
    >>> groups(many_to_one)  # doctest: +SKIP
    {1: {'a', 'b'}, 2: {'c'}, 3: {'e', 'd'}}
    )r   r.   r0   addr2   )Zmany_to_oneZone_to_manyr;   r:   r   r   r   r      s    c                 C   st   ddl }| dks| |jkr$|jjjS t| |jjr6| S t| trL|j| S t| |jjr^| S |  d}t|dS )a  Returns a numpy.random.RandomState or numpy.random.Generator instance
    depending on input.

    Parameters
    ----------
    random_state : int or NumPy RandomState or Generator instance, optional (default=None)
        If int, return a numpy.random.RandomState instance set with seed=int.
        if `numpy.random.RandomState` instance, return it.
        if `numpy.random.Generator` instance, return it.
        if None or numpy.random, return the global random number generator used
        by numpy.random.
    r   NzW cannot be used to create a numpy.random.RandomState or
numpy.random.Generator instance)	r-   randommtrand_randr   RandomStater   	Generatorr    )random_stater8   msgr   r   r   r      s    

c                   @   sh   e Zd ZdddZdd Zdd Zd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S )r   Nc                 C   sR   zdd l }W n$ tk
r0   d}t|t Y nX |d krH|jjj| _n|| _d S )Nr   z.numpy not found, only random.random available.)	r-   ImportErrorwarningswarnImportWarningrF   rG   rH   _rng)selfrngr8   rL   r   r   r   __init__  s    zPythonRandomInterface.__init__c                 C   s
   | j  S NrQ   rF   )rR   r   r   r   rF     s    zPythonRandomInterface.randomc                 C   s   ||| | j    S rU   rV   )rR   r=   rC   r   r   r   uniform"  s    zPythonRandomInterface.uniformc                 C   s4   dd l }t| j|jjr&| j||S | j||S Nr   r-   r   rQ   rF   rJ   integersrandintrR   r=   rC   r8   r   r   r   	randrange%  s    zPythonRandomInterface.randrangec                 C   sF   dd l }t| j|jjr,| jdt|}n| jdt|}|| S rX   )r-   r   rQ   rF   rJ   rZ   r5   r[   )rR   seqr8   idxr   r   r   choice.  s
    zPythonRandomInterface.choicec                 C   s   | j ||S rU   )rQ   normal)rR   musigmar   r   r   gauss7  s    zPythonRandomInterface.gaussc                 C   s   | j |S rU   )rQ   shuffle)rR   r^   r   r   r   re   :  s    zPythonRandomInterface.shufflec                 C   s   | j jt||fddS )NF)sizereplace)rQ   r`   r   )rR   r^   r:   r   r   r   sample@  s    zPythonRandomInterface.samplec                 C   s<   dd l }t| j|jjr*| j||d S | j||d S )Nr      rY   r\   r   r   r   r[   C  s    zPythonRandomInterface.randintc                 C   s   | j d| S )Nri   )rQ   Zexponential)rR   Zscaler   r   r   expovariateK  s    z!PythonRandomInterface.expovariatec                 C   s   | j |S rU   )rQ   Zpareto)rR   shaper   r   r   paretovariateO  s    z#PythonRandomInterface.paretovariate)N)N)__name__
__module____qualname__rT   rF   rW   r]   r`   rd   re   rh   r[   rj   rl   r   r   r   r   r     s   

		c                 C   s   ddl }zVddl}| |j kr,t|j jjW S t| |j j|j jfrLt| W S t| tr\| W S W n tk
rr   Y nX | dks| |kr|j	S t| |j
r| S t| tr|
| S |  d}t|dS )a  Returns a random.Random instance depending on input.

    Parameters
    ----------
    random_state : int or random number generator or None (default=None)
        If int, return a random.Random instance set with seed=int.
        if random.Random instance, return it.
        if None or the `random` package, return the global random number
        generator used by `random`.
        if np.random package, return the global numpy random number
        generator wrapped in a PythonRandomInterface class.
        if np.random.RandomState or np.random.Generator instance, return it
        wrapped in PythonRandomInterface
        if a PythonRandomInterface instance, return it
    r   Nz4 cannot be used to generate a random.Random instance)rF   r-   r   rG   rH   r   rI   rJ   rM   _instRandomr   r    )rK   rF   r8   rL   r   r   r   r   ^  s&    






c              	   C   sZ   t | }t |}zt|}t|}W n, ttfk
rP   t|}t|}Y nX ||kS )aU  Check if nodes are equal.

    Equality here means equal as Python objects.
    Node data must match if included.
    The order of nodes is not relevant.

    Parameters
    ----------
    nodes1, nodes2 : iterables of nodes, or (node, datadict) tuples

    Returns
    -------
    bool
        True if nodes are equal, False otherwise.
    )r   r2   r    r)   fromkeys)Znodes1Znodes2Znlist1Znlist2d1d2r   r   r   r     s    
c                 C   s  ddl m} |t}|t}d}t| D ]\\}}|d |d  }}|dd g}	||| krl|| | |	 }	|	|| |< |	|| |< q(d}
t|D ]\\}
}|d |d  }}|dd g}	||| kr|| | |	 }	|	|| |< |	|| |< q||
k rdS | D ]~\}}| D ]j\}}||kr0  dS ||| krF  dS || | }|D ]&}	||	||	krV   dS qVqqdS )a  Check if edges are equal.

    Equality here means equal as Python objects.
    Edge data must match if included.
    The order of the edges is not relevant.

    Parameters
    ----------
    edges1, edges2 : iterables of with u, v nodes as
        edge tuples (u, v), or
        edge tuples with data dicts (u, v, d), or
        edge tuples with keys and data dicts (u, v, k, d)

    Returns
    -------
    bool
        True if edges are equal, False otherwise.
    r   )r   ri      NFT)collectionsr   r2   r"   r0   count)Zedges1Zedges2r   rs   rt   Zc1eur;   datac2r<   ZnbrdictZnbrZdatalistZ
d2datalistr   r   r   r     s@    

c                 C   s$   | j |j ko"| j|jko"| j|jkS )a  Check if graphs are equal.

    Equality here means equal as Python objects (not isomorphism).
    Node, edge and graph data must match.

    Parameters
    ----------
    graph1, graph2 : graph

    Returns
    -------
    bool
        True if graphs are equal, False otherwise.
    )ZadjZnodesgraph)Zgraph1Zgraph2r   r   r   r     s
    

)N)N)N)N)F)N)N)__doc__sysuuidrN   rv   r   r   collections.abcr   r   r   	itertoolsr   r   Znetworkxr!   __all__r	   r
   r   r'   r*   r   r   r   r   r   r   r   r   r   r   r   r   r   <module>   sD   
$


F
	
L
(7