
    h-S                     ,   S r SSKrSSKrSSKrSSKrSSKJrJr  SSKJ	r	J
r
Jr  SSKJrJr  SSKr/ SQrSS jrS rSS	 jrSS
 jrSS jrS rSS jrS rSS jr " S S\R6                  5      r " S S5      rSS jrS rS r S r!S r"SSSS.S jr#g)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                 8   [        U [        [        -  5      (       a  [        U [        5      (       a  U $ Uc  / nU  HR  n[        U[        [        -  5      (       a  [        U[        5      (       a  UR	                  U5        MG  [        X!5        MT     [        U5      $ )z>Return flattened version of (possibly nested) iterable object.)
isinstancer   r   strappendr
   tuple)objresultitems      E/var/www/html/env/lib/python3.13/site-packages/networkx/utils/misc.pyr
   r
   /   sw    c8e+,,
30D0D
~$5 011Zc5J5JMM$D!	 
 =    c                    [        U [        5      (       dJ  / nU  H@  nSU 3n [        U5      nXB:w  a  [        R
                  " U5      eUR                  U5        MB     U$ [        U 5       HL  u  pRSU 3n[        U[        5      (       a  M!   [        U5      nXB:w  a  [        R
                  " U5      eX@U'   MN     U $ ! [         a    [        R
                  " U5      Sef = f! [         a    [        R
                  " U5      Sef = f)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 w&&v..MM"  X&1!5a	5QB 7""6** ' O%  9&&v.D89  	5""6*4	5s   B=C"="C""Dc                 \     [        X5      $ ! [        [        4 a    [        X5      s $ f = f)zLConvert 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   s3    1$Q00I& 1 %Q001s   
 ++c           
         SSK nUcx  [        U R                  5       5      nU R                  5        H$  u  pEUR	                  UR                  5       5        M&     [        [        U[        [        U5      5      5      5      n[        U5      nUR                  Xf45      nUR                  5        H*  u  pUR                  5        H  u  p X   U
   XyU4'   M     M,     U$ ! [         a     M(  f = f)zQConvert 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GGIDAHHQVVX s1eCFm,-GA
!A]]_EB%)Q$ % ! H  s   C
C+*C+c           
         SSK nUc@  [        U R                  5       5      n[        [	        U[        [        U5      5      5      5      n[        U5      nUR                  U5      nUR                  5        H  u  pgX   nX   XW'   M     U$ )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      sq    Ms1eCFm,-GA
AKu ! Hr!   c                 j    [        U [        5      (       a  [        S5      e[        [	        U 5      5      $ )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                     [        U 5      u  p#[        US5      nUSL a  [        U[        X445      5      $ [        X#5      $ )z&s -> (s0, s1), (s1, s2), (s2, s3), ...NT)r	   rL   r<   r   )rN   cyclicrF   bfirsts        r    r   r      s=    x=DADME~1eAx())q9r!   c                     [        [        5      nU R                  5        H  u  p#X   R                  U5        M     [	        U5      $ )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      s>      c"K!!#1 $r!   c                    SSK nU b  XR                  L a   UR                  R                  R                  $ [	        XR                  R
                  5      (       a  U $ [	        U [        5      (       a  UR                  R                  U 5      $ [	        XR                  R                  5      (       a  U $ U  S3n[        U5      e)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     |yy8yy%%%,		 5 566,$$yy$$\22,		 3 344. * 	*  S/r!   c                   @    \ rS rSrSrSS jrS rS rS rS r	S	 r
S
rg)r   i  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                      SS K nUc&  WR
                  R                  R                  U l        OXl        S U l	        g ! [         a     Sn[        R                  " U[        5         N`f = f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__!PythonRandomViaNumpyBits.__init__'  sZ    	.
 ;		((..DII   	.BCMM#}-	.s   = 'A'&A'c                 6    U R                   R                  5       $ )z7Get the next random number in the range 0.0 <= X < 1.0.rg   rX   rj   s    r    rX   PythonRandomViaNumpyBits.random7  s    yy!!r!   c                     US:  a  [        S5      eUS-   S-  n[        R                  U R                  R	                  U5      S5      nX2S-  U-
  -	  $ )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    getrandbits$PythonRandomViaNumpyBits.getrandbits;  sQ    q5BCCEa<NN499??84e<\A%&&r!   c                 6    U R                   R                  5       $ N)rg   __getstate__rp   s    r    getstate!PythonRandomViaNumpyBits.getstateC  s    yy%%''r!   c                 :    U R                   R                  U5        g r}   )rg   __setstate__)rj   states     r    setstate!PythonRandomViaNumpyBits.setstateF  s    		u%r!   c                     [        S5      e)zDo nothing override method.z2seed() not implemented in PythonRandomViaNumpyBits)NotImplementedError)rj   argskwdss      r    seedPythonRandomViaNumpyBits.seedI  s    !"VWWr!   )rg   rh   r}   )__name__
__module____qualname____firstlineno____doc__rl   rX   rz   r   r   r   __static_attributes__ r!   r    r   r     s&    " "'(&Xr!   r   c                   b    \ rS rSrSrSS jrS rS rSS jrS r	S	 r
S
 rS rS rS rS rSrg)r   iO  zsPythonRandomInterface is included for backward compatibility
New code should use PythonRandomViaNumpyBits instead.
Nc                      SS K nUc&  WR
                  R                  R                  U l        g Xl        g ! [         a     Sn[        R                  " U[        5         NYf = frb   )	r6   rc   rd   re   rf   rX   rY   rZ   rg   ri   s       r    rl   PythonRandomInterface.__init__T  sQ    	.
 ;		((..DII  	.BCMM#}-	.s   6 'A A c                 6    U R                   R                  5       $ r}   ro   rp   s    r    rX   PythonRandomInterface.random`  s    yy!!r!   c                 F    XU-
  U R                   R                  5       -  -   $ r}   ro   )rj   rF   rQ   s      r    uniformPythonRandomInterface.uniformc  s!    ETYY--////r!   c                 8   SS K nUc  SUp!US:  a&  [        U R                  5      nUR                  X5      $ [	        U R                  UR
                  R                  5      (       a  U R                  R                  X5      $ U R                  R                  X5      $ )Nr       )	r6   r   rg   	randranger   rX   r\   integersrandintrj   rF   rQ   rA   tmp_rngs        r    r   PythonRandomInterface.randrangef  s~    9aq"".tyy9G$$Q**dii!4!45599%%a++yy  &&r!   c                    SS K n[        U R                  UR                  R                  5      (       a)  U R                  R                  S[        U5      5      nX   $ U R                  R                  S[        U5      5      nX   $ )Nr   )r6   r   rg   rX   r\   r   r>   r   )rj   seqrA   idxs       r    choicePythonRandomInterface.choiceu  sf    dii!4!455))$$QC1C x ))##As3x0Cxr!   c                 8    U R                   R                  X5      $ r}   )rg   normal)rj   musigmas      r    gaussPythonRandomInterface.gauss~  s    yy**r!   c                 8    U R                   R                  U5      $ r}   )rg   shuffle)rj   r   s     r    r   PythonRandomInterface.shuffle  s    yy  %%r!   c                 L    U R                   R                  [        U5      U4SS9$ )NF)sizereplace)rg   r   r#   )rj   r   rC   s      r    samplePythonRandomInterface.sample  s$    yyS	eDDr!   c                 8   SS K nUS:  a&  [        U R                  5      nUR                  X5      $ [	        U R                  UR
                  R                  5      (       a  U R                  R                  XS-   5      $ U R                  R                  XS-   5      $ )Nr   r      )r6   r   rg   r   r   rX   r\   r   r   s        r    r   PythonRandomInterface.randint  sx    "".tyy9G??1((dii!4!45599%%aQ//yy  E**r!   c                 >    U R                   R                  SU-  5      $ )Nr   )rg   exponential)rj   scales     r    expovariate!PythonRandomInterface.expovariate  s    yy$$QY//r!   c                 8    U R                   R                  U5      $ r}   )rg   pareto)rj   shapes     r    paretovariate#PythonRandomInterface.paretovariate  s    yy&&r!   )rg   r}   )r   r   r   r   r   rl   rX   r   r   r   r   r   r   r   r   r   r   r   r!   r    r   r   O  s?    
"0'+&E	+0'r!   r   c                    U b	  U [         L a  [         R                  $ [        U [         R                  5      (       a  U $ [        U [        5      (       a  [         R                  " U 5      $  SSKn[        U [        [        -  5      (       a  U $ [        XR                   R                  5      (       a  [        U 5      $ XR                   L a)  [        UR                   R                  R                  5      $ [        XR                   R                  5      (       a8  XR                   R                  R                  L a  [        U 5      $ [        U 5      $  U  S3n[        U5      e! [         a     Nf = f)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 `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UlII$7$788+L9999$+BII,<,<,B,BCClII$9$9::yy//555/==(66	 ; NN
OC
S/#  s   *E 
E,+E,c                     [        U 5      n[        U5      n [        U5      n[        U5      nXE:H  $ ! [        [        4 a0    [        R	                  U5      n[        R	                  U5      n XE:H  $ f = f)a)  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     so      &\F&\F#&\&\ 8O 	" #]]6"]]6"8O#s   2 :A21A2c                 Z   SSK Jn  U" [        5      nU" [        5      nSn[        U 5       H4  u  pVUS   US   pUSS /n	XU   ;   a
  X7   U   U	-   n	XU   U'   XU   U'   M6     Sn
[        U5       H4  u  pUS   US   pUSS /n	XU   ;   a
  XG   U   U	-   n	XU   U'   XU   U'   M6     XZ:w  a  gUR	                  5        Hi  u  pUR	                  5        HP  u  pX;  a      gXU   ;  a      gXK   U   nU H+  n	UR                  U	5      UR                  U	5      :w  d  M)        g   MR     Mk     g)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     sY   & (	T	B	T	B	
B6"tQqT1!"w1:58d?D1a1a # 
B6"tQqT1!"w1:58d?D1a1a # 
xhhj
$]]_MC{Q%sJ >>$':+;+;D+AA  ! - ! r!   c                     U R                   UR                   :H  =(       a9    U R                  UR                  :H  =(       a    U R                  UR                  :H  $ )zCheck 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                 N    [        U SS5      =n(       a  UR                  5         gg)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                >   Uc  [         R                  nU b  U OUn[        U[        5      (       a  UR	                  S5      OUR	                  5       n[        U[        5      (       a  UR                  S5      OUR                  5       nUbH  U(       a  U(       d  [         R                  " S5      eU(       d  U(       a  [         R                  " S5      eUbH  U(       a  U(       d  [         R                  " S5      eU(       d  U(       a  [         R                  " S5      eU$ )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!   r}   )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!   