o
    h-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   g/var/www/html/construction_image-detection-poc/venv/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ii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/   r0   npskvnak1r'   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)	r1   r2   r3   r6   r7   r8   r9   r:   r4   )r/   r0   r<   r=   r@   rA   rB   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   rE   r7   r   )rG   cyclicrA   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   r2   r4   addr6   )many_to_one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)	r1   randommtrand_randr   RandomStater!   	Generatorr"   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.)
r1   ImportErrorwarningswarnImportWarningrN   rO   rP   _rng
gauss_nextselfrngr<   rU   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.r[   rN   r^   r   r   r   rN   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_bytesr[   bytes)r^   r>   numbytesxr   r   r   getrandbits;  s
   z$PythonRandomViaNumpyBits.getrandbitsc                 C   ra   N)r[   __getstate__rc   r   r   r   getstateC     
z!PythonRandomViaNumpyBits.getstatec                 C   s   | j | d S rl   )r[   __setstate__)r^   stater   r   r   setstateF     z!PythonRandomViaNumpyBits.setstatec                 O   s   t d)zDo nothing override method.z2seed() not implemented in PythonRandomViaNumpyBits)NotImplementedError)r^   argskwdsr   r   r   seedI  s   zPythonRandomViaNumpyBits.seedrl   )
__name__
__module____qualname____doc__r`   rN   rk   rn   rr   rw   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 rV   )	r1   rW   rX   rY   rZ   rN   rO   rP   r[   r]   r   r   r   r`   T  s   
zPythonRandomInterface.__init__c                 C   ra   rl   rb   rc   r   r   r   rN   `  ro   zPythonRandomInterface.randomc                 C   s   ||| | j    S rl   rb   )r^   rA   rI   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       )	r1   r   r[   	randranger   rN   rR   integersrandintr^   rA   rI   r<   tmp_rngr   r   r   r~   f  s   

zPythonRandomInterface.randrangec                 C   sL   dd l }t| j|jjr| jdt|}|| S | jdt|}|| S )Nr   )r1   r   r[   rN   rR   r   r9   r   )r^   seqr<   idxr   r   r   choiceu  s   zPythonRandomInterface.choicec                 C   s   | j ||S rl   )r[   normal)r^   musigmar   r   r   gauss~  s   zPythonRandomInterface.gaussc                 C      | j |S rl   )r[   shuffle)r^   r   r   r   r   r        zPythonRandomInterface.shufflec                 C   s   | j jt||fddS )NF)sizereplace)r[   r   r    )r^   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   r}      )r1   r   r[   r   r   rN   rR   r   r   r   r   r   r     s   
zPythonRandomInterface.randintc                 C   s   | j d| S )Nr   )r[   exponential)r^   scaler   r   r   expovariate  rs   z!PythonRandomInterface.expovariatec                 C   r   rl   )r[   pareto)r^   shaper   r   r   paretovariate  r   z#PythonRandomInterface.paretovariaterl   )rx   ry   rz   r{   r`   rN   r|   r~   r   r   r   r   r   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)rN   _instr   Randomr!   r1   rW   r   r   rR   rO   rP   rQ   r"   rS   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    r6   r"   r-   fromkeys)nodes1nodes2nlist1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   r6   r%   r4   count)edges1edges2r   r   r   c1eur?   datac2r@   nbrdictnbrdatalist
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.
    )adjnodesgraph)graph1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.
    __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#   Graphr   typeis_directedis_multigraphr$   )create_usingr   r   r   r   
G_directedG_multigraphr   r   r   check_create_using\  s    



r   rl   )F)$r{   rN   sysuuidrX   r   r   r   collections.abcr   r   r   	itertoolsr   r   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	