o
    ]Zh-S                     @   s  d Z ddl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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ejZG dd dZd+ddZd d! Zd"d# Z d$d% Z!d&d' Z"dddd(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PythonRandomViaNumpyBitsnodes_equaledges_equalgraphs_equal_clear_cachec                 C   sh   t | ttB rt | tr| S |du rg }| D ]}t |ttB r$t |tr*|| qt|| qt|S )z>Return flattened version of (possibly nested) iterable object.N)
isinstancer   r   strappendr	   tuple)objresultitem r   B/var/www/auris/lib/python3.10/site-packages/networkx/utils/misc.pyr	   /   s   r	   c              	   C   s   t | ts5g }| D ])}d| }zt|}W n ty#   t|dw ||kr-t||| q	|S t| D ]0\}}d| }t |trHq9zt|}W n ty[   t|dw ||kret||| |< q9| 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iiZindxr   r   r   r
   =   s4   
	





r
   c              	   C   s.   zt | |W S  ttfy   t| | Y S w )zPConvert a dictionary of dictionaries to a numpy array
    with optional mapping.)_dict_to_numpy_array2AttributeError	TypeError_dict_to_numpy_array1)dmappingr   r   r   r   a   s
   r   c              
   C   s   ddl }|du r)t|  }|  D ]\}}||  qtt|tt|}t|}|	||f}| D ]"\}}	| D ]\}
}z| | |
 ||	|f< W q@ t
yY   Y q@w q8|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*   l   s"   r*   c                 C   sn   ddl }|du rt|  }tt|tt|}t|}||}| D ]\}}|| }| | ||< q&|S )zJConvert a dictionary of numbers to a 1d numpy array with optional mapping.r   N)	r0   r1   r2   r5   r6   r7   r8   r9   r3   )r.   r/   r;   r<   r?   r@   rA   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   
?r   Fc                 C   s:   t | \}}t|d}|du rt|t||fS t||S )z&s -> (s0, s1), (s1, s2), (s2, s3), ...NT)r   rC   r6   r   )rE   Zcyclicr@   bfirstr   r   r   r      s
   

r   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   r1   r3   addr5   )Zmany_to_oneZone_to_manyr>   r=   r   r   r   r      s   r   c                 C   sp   ddl }| du s| |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)	r0   randommtrand_randr   RandomStater!   	Generatorr"   Zrandom_stater;   msgr   r   r   r      s   

r   c                   @   sB   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S )r   a  Provide the random.random algorithms using a numpy.random bit generator

    The intent is to allow people to contribute code that uses Python's random
    library, but still allow users to provide a single easily controlled random
    bit-stream for all work with NetworkX. This implementation is based on helpful
    comments and code from Robert Kern on NumPy's GitHub Issue #24458.

    This implementation supersedes that of `PythonRandomInterface` which rewrote
    methods to account for subtle differences in API between `random` and
    `numpy.random`. Instead this subclasses `random.Random` and overwrites
    the methods `random`, `getrandbits`, `getstate`, `setstate` and `seed`.
    It makes them use the rng values from an input numpy `RandomState` or `Generator`.
    Those few methods allow the rest of the `random.Random` methods to provide
    the API interface of `random.random` while using randomness generated by
    a numpy generator.
    Nc                 C   sV   zdd l }W n ty   d}t|t Y nw |d u r#|jjj| _n|| _d | _	d S Nr   z.numpy not found, only random.random available.)
r0   ImportErrorwarningswarnImportWarningrI   rJ   rK   _rng
gauss_nextselfrngr;   rO   r   r   r   __init__'  s   
z!PythonRandomViaNumpyBits.__init__c                 C   
   | j  S )z7Get the next random number in the range 0.0 <= X < 1.0.rU   rI   rX   r   r   r   rI   7  s   
zPythonRandomViaNumpyBits.randomc                 C   s@   |dk rt d|d d }t| j|d}||d | ? S )z:getrandbits(k) -> x.  Generates an int with k random bits.r   z#number of bits must be non-negative      big)r"   r!   
from_bytesrU   bytes)rX   r=   numbytesxr   r   r   getrandbits;  s
   z$PythonRandomViaNumpyBits.getrandbitsc                 C   r[   N)rU   __getstate__r]   r   r   r   getstateC     
z!PythonRandomViaNumpyBits.getstatec                 C   s   | j | d S rf   )rU   __setstate__)rX   stater   r   r   setstateF     z!PythonRandomViaNumpyBits.setstatec                 O   s   t d)zDo nothing override method.z2seed() not implemented in PythonRandomViaNumpyBits)NotImplementedError)rX   argskwdsr   r   r   seedI  s   zPythonRandomViaNumpyBits.seedrf   )
__name__
__module____qualname____doc__rZ   rI   re   rh   rl   rq   r   r   r   r   r     s    
r   c                   @   sl   e Zd 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   z{PythonRandomInterface is included for backward compatibility
    New code should use PythonRandomViaNumpyBits instead.
    Nc                 C   sR   zdd l }W n ty   d}t|t Y nw |d u r$|jjj| _d S || _d S rP   )	r0   rQ   rR   rS   rT   rI   rJ   rK   rU   rW   r   r   r   rZ   T  s   
zPythonRandomInterface.__init__c                 C   r[   rf   r\   r]   r   r   r   rI   `  ri   zPythonRandomInterface.randomc                 C   s   ||| | j    S rf   r\   )rX   r@   rF   r   r   r   uniformc  s   zPythonRandomInterface.uniformc                 C   sd   dd l }|d u rd|}}|dkrt| j}|||S t| j|jjr+| j||S | j||S )Nr       )	r0   r   rU   	randranger   rI   rM   integersrandintrX   r@   rF   r;   Ztmp_rngr   r   r   rx   f  s   

zPythonRandomInterface.randrangec                 C   sL   dd l }t| j|jjr| jdt|}|| S | jdt|}|| S )Nr   )r0   r   rU   rI   rM   ry   r8   rz   )rX   seqr;   idxr   r   r   choiceu  s   zPythonRandomInterface.choicec                 C   s   | j ||S rf   )rU   normal)rX   musigmar   r   r   gauss~  s   zPythonRandomInterface.gaussc                 C      | j |S rf   )rU   shuffle)rX   r|   r   r   r   r        zPythonRandomInterface.shufflec                 C   s   | j jt||fddS )NF)sizereplace)rU   r~   r    )rX   r|   r=   r   r   r   sample  s   zPythonRandomInterface.samplec                 C   sZ   dd l }|dkrt| j}|||S t| j|jjr$| j||d S | j||d S )Nr   rw      )r0   r   rU   rz   r   rI   rM   ry   r{   r   r   r   rz     s   
zPythonRandomInterface.randintc                 C   s   | j d| S )Nr   )rU   Zexponential)rX   scaler   r   r   expovariate  rm   z!PythonRandomInterface.expovariatec                 C   r   rf   )rU   Zpareto)rX   shaper   r   r   paretovariate  r   z#PythonRandomInterface.paretovariaterf   )rr   rs   rt   ru   rZ   rI   rv   rx   r~   r   r   r   rz   r   r   r   r   r   r   r   O  s    

	r   c                 C   s   | du s| t u rt jS t| t jr| S t| trt | S zddl}W n	 ty,   Y n7w t| ttB r6| S t| |j j	rAt| S | |j u rMt|j j
jS t| |j jrc| |j j
ju r_t| S t| S |  d}t|)a5  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 `np.random` package, return the global random number
          generator used by `np.random`.
        - If an `np.random.Generator` instance, or the `np.random` package, or
          the global numpy random number generator, then return it.
          wrapped in a `PythonRandomViaNumpyBits` class.
        - If a `PythonRandomViaNumpyBits` instance, return it.
        - If a `PythonRandomInterface` instance, return it.
        - If a `np.random.RandomState` instance and not the global numpy default,
          return it wrapped in `PythonRandomInterface` for backward bit-stream
          matching with legacy code.

    Notes
    -----
    - A diagram intending to illustrate the relationships behind our support
      for numpy random numbers is called
      `NetworkX Numpy Random Numbers <https://excalidraw.com/#room=b5303f2b03d3af7ccc6a,e5ZDIWdWWCTTsg8OqoRvPA>`_.
    - More discussion about this support also appears in
      `gh-6869#comment <https://github.com/networkx/networkx/pull/6869#issuecomment-1944799534>`_.
    - Wrappers of numpy.random number generators allow them to mimic the Python random
      number generation algorithms. For example, Python can create arbitrarily large
      random ints, and the wrappers use Numpy bit-streams with CPython's random module
      to choose arbitrarily large random integers too.
    - We provide two wrapper classes:
      `PythonRandomViaNumpyBits` is usually what you want and is always used for
      `np.Generator` instances. But for users who need to recreate random numbers
      produced in NetworkX 3.2 or earlier, we maintain the `PythonRandomInterface`
      wrapper as well. We use it only used if passed a (non-default) `np.RandomState`
      instance pre-initialized from a seed. Otherwise the newer wrapper is used.
    Nr   z4 cannot be used to generate a random.Random instance)rI   _instr   Randomr!   r0   rQ   r   r   rM   rJ   rK   rL   r"   rN   r   r   r   r     s.   %



r   c              	   C   s\   t | }t |}zt|}t|}W ||kS  ttfy-   t|}t|}Y ||kS w )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    r5   r"   r,   fromkeys)Znodes1Znodes2Znlist1Znlist2d1d2r   r   r   r     s   

r   c                 C   s|  ddl m} |t}|t}d}t| D ].\}}|d |d }}|dd g}	||| v r6|| | |	 }	|	|| |< |	|| |< qd}
t|D ].\}
}|d |d }}|dd g}	||| v rk|| | |	 }	|	|| |< |	|| |< qI||
kr~dS | D ]9\}}| D ]0\}}||vr  dS ||| vr  dS || | }|D ]}	||	||	kr   dS qqqd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   r5   r%   r3   count)Zedges1Zedges2r   r   r   c1eur>   datac2r?   ZnbrdictZnbrZdatalistZ
d2datalistr   r   r   r     sF   
	r   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adjnodesgraph)Zgraph1Zgraph2r   r   r   r   =  s
   

r   c                 C   s    t | dd }r|  dS dS )zClear the cache of a graph (currently stores converted graphs).

    Caching is controlled via ``nx.config.cache_converted_graphs`` configuration.
    Z__networkx_cache__N)getattrclear)Gcacher   r   r   r   S  s   r   )directed
multigraphdefaultc                C   s   |du rt j}| dur| n|}t|tr|dn| }t|tr'|dn| }|durA|r8|s8t d|sA|rAt d|durW|rN|sNt d|sW|rWt d|S )a!  Assert that create_using has good properties

    This checks for desired directedness and multi-edge properties.
    It returns `create_using` unless that is `None` when it returns
    the optionally specified default value.

    Parameters
    ----------
    create_using : None, graph class or instance
        The input value of create_using for a function.
    directed : None or bool
        Whether to check `create_using.is_directed() == directed`.
        If None, do not assert directedness.
    multigraph : None or bool
        Whether to check `create_using.is_multigraph() == multigraph`.
        If None, do not assert multi-edge property.
    default : None or graph class
        The graph class to return if create_using is None.

    Returns
    -------
    create_using : graph class or instance
        The provided graph class or instance, or if None, the `default` value.

    Raises
    ------
    NetworkXError
        When `create_using` doesn't match the properties specified by `directed`
        or `multigraph` parameters.
    Nzcreate_using must be directedz!create_using must not be directedz"create_using must be a multi-graphz&create_using must not be a multi-graph)r#   ZGraphr   typeZis_directedZis_multigraphr$   )Zcreate_usingr   r   r   r   Z
G_directedZG_multigraphr   r   r   check_create_using\  s    



r   rf   )F)$ru   rI   sysuuidrR   r   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   r   r   r   r   <module>   s6    

$


F	
:
ZB7	