
    Gd8                         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g dZddZd Zdd	Zdd
ZddZd ZddZd ZddZ G d d          ZddZd Zd Z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                 F   t          | t          t          f          rt          | t                    r| S |g }| D ]Y}t          |t          t          f          rt          |t                    r|                    |           It          ||           Zt          |          S )z>Return flattened version of (possibly nested) iterable object.)
isinstancer   r   strappendr
   tuple)objresultitems      3lib/python3.11/site-packages/networkx/utils/misc.pyr
   r
   ,   s    cHe,-- C1E1E 
~ " "$5 122 	"js6K6K 	"MM$D&!!!!==    c                    t          | t                    sqg }| D ]j}d| }	 t          |          }n## t          $ r t	          j        |          dw xY w||k    rt	          j        |          |                    |           k|S t          |           D ]s\  }}d| }t          |t                    r 	 t          |          }n## t          $ r t	          j        |          dw xY w||k    rt	          j        |          || |<   t| 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nxNetworkXErrorr   	enumerate)sequencer   ierrmsgiiindxs         r   r   r   :   sR    h%%  	 	A9a99F9VV 9 9 9&v..D89Qww&v...MM"X&& 
 
a5!55a 		5QBB 	5 	5 	5"6**4	577"6***Os   2 A7C C'c                 r    	 t          | |          S # t          t          f$ r t          | |          cY S w xY w)zPConvert a dictionary of dictionaries to a numpy array
    with optional mapping.)_dict_to_numpy_array2AttributeError	TypeError_dict_to_numpy_array1)dmappings     r   r   r   ^   sO    1$Q000I& 1 1 1 %Q000001s    !66c           
      @   ddl }|t          |                                           }|                                 D ],\  }}|                    |                                           -t          t          |t          t          |                                        }t          |          }|	                    ||f          }|                                D ]C\  }}	|                                D ])\  }
}	 | |         |
         ||	|f<   # t          $ r Y &w xY wD|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)r1   r2   npskvnak1r(   k2js               r   r-   r-   i   s!   
 MMGGII 	 	DAqHHQVVXXs1eCFFmm,,--GA
!QA  A]]__ 	 	EBB%)!Q$   	
 Hs   9D
DDc           
      d   ddl }|Xt          |                                           }t          t	          |t          t          |                                        }t          |          }|                    |          }|                                D ]\  }}||         }| |         ||<   |S )zJConvert a dictionary of numbers to a 1d numpy array with optional mapping.r   N)	r4   r5   r6   r9   r:   r;   r<   r=   r7   )r1   r2   r?   r@   rC   rD   rE   r(   s           r   r0   r0      s    MMs1eCFFmm,,--GA
A  ABKu!Hr   c                     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)iterables    r   r   r      s;    ~ (H%% MKLLLXr   Fc                     t          |           \  }}t          |d          }|du rt          |t          ||f                    S t          ||          S )z&s -> (s0, s1), (s1, s2), (s2, s3), ...NT)r	   rJ   r:   r   )rL   cyclicrD   bfirsts        r   r   r      sQ    x==DAqDMME~~1eAx(()))q!99r   c                     t          t                    }|                                 D ] \  }}||                             |           !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   r5   r7   addr9   )many_to_oneone_to_manyrB   rA   s       r   r   r      sY      c""K!!##  1A1r   c                 8   ddl }| 	| |j        u r|j        j        j        S t	          | |j        j                  r| S t	          | t                    r|j                            |           S t	          | |j        j                  r| S |  d}t          |          )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)	r4   randommtrand_randr   RandomStater"   	Generatorr#   )random_stater?   msgs      r   r   r      s     |ry88y%%,	 566 ,$$ 3y$$\222,	 344  	* 	* 	*  S//r   c                   T    e Zd ZddZd Zd ZddZd Zd Zd Z	d	 Z
d
 Zd Zd ZdS )r   Nc                     	 dd l }n,# t          $ r d}t          j        |t                     Y nw xY w||j        j        j        | _        d S || _        d S )Nr   z.numpy not found, only random.random available.)	r4   ImportErrorwarningswarnImportWarningrV   rW   rX   _rng)selfrngr?   r\   s       r   __init__zPythonRandomInterface.__init__  ss    	. 	. 	. 	.BCM#}-----	. ;	(.DIIIDIIIs    &00c                 4    | j                                         S Nrc   rV   )rd   s    r   rV   zPythonRandomInterface.random  s    y!!!r   c                 F    |||z
  | j                                         z  z   S rh   ri   )rd   rD   rO   s      r   uniformzPythonRandomInterface.uniform"  s$    AETY--/////r   c                     dd l }t          | j        |j        j                  r| j                            ||          S | j                            ||          S Nr   r4   r   rc   rV   rZ   integersrandintrd   rD   rO   r?   s       r   	randrangezPythonRandomInterface.randrange%  sW    di!455 	,9%%a+++y  A&&&r   c                     dd l }t          | j        |j        j                  r)| j                            dt          |                    }n(| j                            dt          |                    }||         S rm   )r4   r   rc   rV   rZ   ro   r<   rp   )rd   seqr?   idxs       r   choicezPythonRandomInterface.choice.  sl    di!455 	1)$$QC11CC)##As3xx00C3xr   c                 8    | j                             ||          S rh   )rc   normal)rd   musigmas      r   gausszPythonRandomInterface.gauss7  s    yE***r   c                 6    | j                             |          S rh   )rc   shuffle)rd   rt   s     r   r}   zPythonRandomInterface.shuffle:  s    y  %%%r   c                 X    | j                             t          |          |fd          S )NF)sizereplace)rc   rv   r!   )rd   rt   rA   s      r   samplezPythonRandomInterface.sample@  s'    yS		eDDDr   c                     dd l }t          | j        |j        j                  r| j                            ||dz             S | j                            ||dz             S )Nr      rn   rq   s       r   rp   zPythonRandomInterface.randintC  s_    di!455 	09%%aQ///y  AE***r   c                 <    | j                             d|z            S )Nr   )rc   exponential)rd   scales     r   expovariatez!PythonRandomInterface.expovariateK  s    y$$QY///r   c                 6    | j                             |          S rh   )rc   pareto)rd   shapes     r   paretovariatez#PythonRandomInterface.paretovariateO  s    y&&&r   rh   )__name__
__module____qualname__rf   rV   rk   rr   rv   r{   r}   r   rp   r   r    r   r   r   r     s        
 
 
 
" " "0 0 0' ' ' '  + + +& & &E E E+ + +0 0 0' ' ' ' 'r   r   c                    ddl }	 ddl}| |j         u rt          |j         j        j                  S t          | |j         j        |j         j        f          rt          |           S t          | t                    r| S n# t          $ r Y nw xY w| | |u r|j	        S t          | |j
                  r| S t          | t                    r|
                    |           S |  d}t          |          )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)rV   r4   r   rW   rX   r   rY   rZ   r_   _instRandomr"   r#   )r[   rV   r?   r\   s       r   r   r   ^  s      MMM
29$$()9)?@@@lRY%:BI<O$PQQ 	7(666l$9:: 	 	     |v55|,.. ,$$ +}}\***
O
O
OC
S//s   *A> 4A> &A> >
B
Bc                     t          |           }t          |          }	 t          |          }t          |          }nK# t          t          f$ r7 t                              |          }t                              |          }Y nw xY w||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!   r9   r#   r/   fromkeys)nodes1nodes2nlist1nlist2d1d2s         r   r   r     s      &\\F&\\F#&\\&\\	" # # #]]6""]]6""# 8Os   ? ABBc                 
   ddl m}  |t                    } |t                    }d}t          |           D ]Q\  }}|d         |d         }}|dd         g}	|||         v r||         |         |	z   }	|	||         |<   |	||         |<   Rd}
t          |          D ]Q\  }
}|d         |d         }}|dd         g}	|||         v r||         |         |	z   }	|	||         |<   |	||         |<   R||
k    rdS |                                D ]y\  }}|                                D ]_\  }}||vr  dS |||         vr  dS ||         |         }|D ]3}	|                    |	          |                    |	          k    r   dS 4`zd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   r      NFT)collectionsr   r9   r&   r7   count)edges1edges2r   r   r   c1eurB   datac2rC   nbrdictnbrdatalist
d2datalists                   r   r   r     s   & ('''''	T		B	T		B	
B6""  AtQqT1!""w1::a58d?D1a1a	
B6""  AtQqT1!""w1::a58d?D1a1a	Rxxuhhjj 	! 	!
7$]]__ 	! 	!MC{{uuu"Q%uuuAsJ  ! !>>$'':+;+;D+A+AAA 5555 B!	! 4r   c                 b    | 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.
    )adjnodesgraph)graph1graph2s     r   r   r     s7      	
fj  	)LFL(	)LFL(r   rh   )F)__doc__sysuuidr`   r   r   r   collections.abcr   r   r   	itertoolsr   r	   networkxr$   __all__r
   r   r   r-   r0   r   r   r   r   r   r   r   r   r   r   r   r   <module>r      s    


   * * * * * * * * 5 5 5 5 5 5 5 5 5 5                      *   ! ! !H1 1 1 1   .   B  B  B L     ,   <>' >' >' >' >' >' >' >'X% % % %P  64 4 4n    r   