
    wg-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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ej6                        Z G d d      ZddZd Zd Z d Z!d Z"dddddZ#y)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                 
   t        | t        t        z        rt        | t              r| S |g }| D ]G  }t        |t        t        z        rt        |t              r|j	                  |       <t        ||       I t        |      S )z>Return flattened version of (possibly nested) iterable object.)
isinstancer   r   strappendr
   tuple)objresultitems      X/home/mcse/projects/flask/flask-venv/lib/python3.12/site-packages/networkx/utils/misc.pyr
   r
   /   sr    c8e+,
30D
~ "$5 01Zc5JMM$D&!	"
 =    c                    t        | t              sGg }| D ]>  }d| }	 t        |      }||k7  rt	        j
                  |      |j                  |       @ |S t        |       D ]F  \  }}d| }t        |t              r	 t        |      }||k7  rt	        j
                  |      || |<   H | S # t        $ r t	        j
                  |      dw xY w# t        $ r t	        j
                  |      dw xY w)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   =   s    h% 	A5aS9F9V Qw&&v..MM"	 X& 
a1!5a	5QB 7""6**
 O%  9&&v.D89  	5""6*4	5s   B. C. C C1c                 ^    	 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   a   s7    1$Q00I& 1 %Q001s    ,,c           
         ddl }|wt        | j                               }| j                         D ]$  \  }}|j	                  |j                                & t        t        |t        t        |                        }t        |      }|j                  ||f      }|j                         D ]+  \  }}	|j                         D ]  \  }
}	 | |   |
   ||	|f<    - |S # t        $ r Y %w xY w)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)r3   r4   npskvnak1r*   k2js               r    r/   r/   l   s    
 MGGI 	DAqHHQVVX	s1eCFm,-GA
!QA A]]_ 	EBB%)!Q$	 H  s   	C	C('C(c           
         ddl }|@t        | j                               }t        t	        |t        t        |                        }t        |      }|j                  |      }|j                         D ]  \  }}||   }| |   ||<    |S )zJConvert a dictionary of numbers to a 1d numpy array with optional mapping.r   N)	r6   r7   r8   r;   r<   r=   r>   r?   r9   )r3   r4   rA   rB   rE   rF   rG   r*   s           r    r2   r2      s~    Ms1eCFm,-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%KLLXr!   c                     t        |       \  }}t        |d      }|du rt        |t        ||f            S t        ||      S )z&s -> (s0, s1), (s1, s2), (s2, s3), ...NT)r	   rL   r<   r   )rN   cyclicrF   bfirsts        r    r   r      sC    x=DAqDME~1eAx())q!9r!   c                     t        t              }| j                         D ]  \  }}||   j                  |        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   r7   r9   addr;   )many_to_oneone_to_manyrD   rC   s       r    r   r      sG      c"K!!# 1A1r!   c                 h   ddl }| | |j                  u r |j                  j                  j                  S t	        | |j                  j
                        r| S t	        | t              r|j                  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)	r6   randommtrand_randr   RandomStater$   	Generatorr%   random_staterA   msgs      r    r   r      s     |ryy8yy%%%,		 5 56,$yy$$\22,		 3 34. * 	*  S/r!   c                   6    e Zd ZdZd	dZd Zd Zd Zd Zd Z	y)
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                     	 dd l }|-j
                  j                  j                  | _        d | _	        y || _        d | _	        y # t        $ r d}t        j                  |t               Y ew xY wNr   z.numpy not found, only random.random available.)
r6   ImportErrorwarningswarnImportWarningrX   rY   rZ   _rng
gauss_nextselfrngrA   r_   s       r    __init__z!PythonRandomViaNumpyBits.__init__'  sg    	.
 ;		((..DI 	 DI   	.BCMM#}-	.s   A %A,+A,c                 6    | j                   j                         S )z7Get the next random number in the range 0.0 <= X < 1.0.rg   rX   rj   s    r    rX   zPythonRandomViaNumpyBits.random7  s    yy!!r!   c                     |dk  rt        d      |dz   dz  }t        j                  | j                  j	                  |      d      }||dz  |z
  z	  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_bytesrg   bytes)rj   rC   numbytesxs       r    getrandbitsz$PythonRandomViaNumpyBits.getrandbits;  sS    q5BCCEa<NN499??84e<X\A%&&r!   c                 6    | j                   j                         S N)rg   __getstate__ro   s    r    getstatez!PythonRandomViaNumpyBits.getstateC  s    yy%%''r!   c                 :    | j                   j                  |       y rz   )rg   __setstate__)rj   states     r    setstatez!PythonRandomViaNumpyBits.setstateF  s    		u%r!   c                     t        d      )zDo nothing override method.z2seed() not implemented in PythonRandomViaNumpyBits)NotImplementedError)rj   argskwdss      r    seedzPythonRandomViaNumpyBits.seedI  s    !"VWWr!   rz   )
__name__
__module____qualname____doc__rl   rX   rx   r|   r   r    r!   r    r   r     s&    " "'(&Xr!   r   c                   V    e Zd 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y)r   z{PythonRandomInterface is included for backward compatibility
    New code should use PythonRandomViaNumpyBits instead.
    Nc                     	 dd l }|&j
                  j                  j                  | _        y || _        y # t        $ r d}t        j                  |t               Y Ww xY wrb   )	r6   rc   rd   re   rf   rX   rY   rZ   rg   ri   s       r    rl   zPythonRandomInterface.__init__T  sS    	.
 ;		((..DIDI  	.BCMM#}-	.s   6 %AAc                 6    | j                   j                         S rz   rn   ro   s    r    rX   zPythonRandomInterface.random`  s    yy!!r!   c                 H    |||z
  | j                   j                         z  z   S rz   rn   )rj   rF   rQ   s      r    uniformzPythonRandomInterface.uniformc  s#    AETYY--////r!   c                 2   dd l }|d|}}|dkD  r't        | j                        }|j                  ||      S t	        | j                  |j
                  j                        r| j                  j                  ||      S | j                  j                  ||      S )Nr       )	r6   r   rg   	randranger   rX   r\   integersrandintrj   rF   rQ   rA   tmp_rngs        r    r   zPythonRandomInterface.randrangef  s    9aqA"".tyy9G$$Q**dii!4!4599%%a++yy  A&&r!   c                    dd l }t        | j                  |j                  j                        r*| j                  j                  dt        |            }||   S | j                  j                  dt        |            }||   S )Nr   )r6   r   rg   rX   r\   r   r>   r   )rj   seqrA   idxs       r    choicezPythonRandomInterface.choiceu  sg    dii!4!45))$$QC1C 3x ))##As3x0C3xr!   c                 :    | j                   j                  ||      S rz   )rg   normal)rj   musigmas      r    gausszPythonRandomInterface.gauss~  s    yyE**r!   c                 8    | j                   j                  |      S rz   )rg   shuffle)rj   r   s     r    r   zPythonRandomInterface.shuffle  s    yy  %%r!   c                 R    | j                   j                  t        |      |fd      S )NF)sizereplace)rg   r   r#   )rj   r   rC   s      r    samplezPythonRandomInterface.sample  s$    yyS	eDDr!   c                 2   dd l }|dkD  r't        | j                        }|j                  ||      S t	        | j                  |j
                  j                        r| j                  j                  ||dz         S | j                  j                  ||dz         S )Nr   r      )r6   r   rg   r   r   rX   r\   r   r   s        r    r   zPythonRandomInterface.randint  s{    "".tyy9G??1a((dii!4!4599%%aQ//yy  AE**r!   c                 >    | j                   j                  d|z        S )Nr   )rg   exponential)rj   scales     r    expovariatez!PythonRandomInterface.expovariate  s    yy$$QY//r!   c                 8    | j                   j                  |      S rz   )rg   pareto)rj   shapes     r    paretovariatez#PythonRandomInterface.paretovariate  s    yy&&r!   rz   )r   r   r   r   rl   rX   r   r   r   r   r   r   r   r   r   r   r!   r    r   r   O  s?    
"0'+&E	+0'r!   r   c                    | | t         u rt         j                  S t        | t         j                        r| S t        | t              rt        j                  |       S 	 ddl}t        | t        t        z        r| S t        | |j                   j                        rt        |       S | |j                   u r)t        |j                   j                  j                        S t        | |j                   j                        r8| |j                   j                  j                  u rt        |       S t        |       S |  d}t        |      # t        $ r Y w xY w)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)rX   _instr   Randomr$   r6   r   r   r\   rY   rZ   r[   rc   r%   r]   s      r    r   r     s   J |v5||,.,$}}\**7 l$9<T$TUlBII$7$78+L99299$+BII,<,<,B,BCClBII$9$9:ryy//555/==(66NN
OC
S/#  s   E 	EEc                     t        |       }t        |      }	 t        |      }t        |      }||k(  S # t        t        f$ r1 t        j	                  |      }t        j	                  |      }Y ||k(  S w xY 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#   r;   r%   r1   fromkeys)nodes1nodes2nlist1nlist2d1d2s         r    r   r     ss      &\F&\F#&\&\ 8O 	" #]]6"]]6"8O#s   3 9A32A3c                 V   ddl m}  |t              } |t              }d}t        |       D ]7  \  }}|d   |d   }}|dd g}	|||   v r||   |   |	z   }	|	||   |<   |	||   |<   9 d}
t        |      D ]7  \  }
}|d   |d   }}|dd g}	|||   v r||   |   |	z   }	|	||   |<   |	||   |<   9 ||
k7  ry|j	                         D ]d  \  }}|j	                         D ]L  \  }}||vr  y|||   vr  y||   |   }|D ])  }	|j                  |	      |j                  |	      k7  s'   y N f y)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   r;   r(   r9   count)edges1edges2r   r   r   c1eurD   datac2rE   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 
Rxhhj 	!
7$]]_ 	!MC{"Q%AsJ  !>>$':+;+;D+AA !	!	! r!   c                     | j                   |j                   k(  xr4 | j                  |j                  k(  xr | 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   =  sC      	

fjj  	)LLFLL(	)LLFLL(r!   c                 D    t        | dd      x}r|j                          yy)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caches     r    r   r   S  s'    
 /66u6 7r!   )directed
multigraphdefaultc                   |t         j                  }| | n|}t        |t              r|j	                  d      n|j	                         }t        |t              r|j                  d      n|j                         }|2|r|st        j                  d      |s|rt        j                  d      |2|r|st        j                  d      |s|rt        j                  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_multigraphs          r    check_create_usingr   \  s    > (($0gA(21d(;t$J,6q$,?1??4(Q__EVLJ""#BCCJ""#FGGl""#GHHl""#KLLHr!   rz   )F)$r   rX   sysuuidrd   r   r   r   collections.abcr   r   r   	itertoolsr   r	   networkxr&   __all__r
   r   r   r/   r2   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r!   r    <module>r      s     
   * 5 5   .!H1.B L,<6Xv}} 6XtL' L't?D64n, 26$PT 1r!   