+
    )i<Y                     2   R t ^ RIt^ RIt^ RIt^ RIHt ^ RIHtHtH	t	 ^ RIH
t
HtHt ^ RIt. ROtRR ltR tRR	 ltRR
 ltRR ltR tRR ltR tRR lt ! R R]P2                  4      t ! R R4      tRR ltR tRR/R ltR tR t RRRRRR/R lt!R# )a  
Miscellaneous Helpers for NetworkX.

These are not imported into the base networkx namespace but
can be accessed, for example, as

>>> import networkx as nx
>>> nx.utils.make_list_of_ints({1, 2, 3})
[1, 2, 3]
>>> nx.utils.arbitrary_element({5, 1, 7})  # doctest: +SKIP
1
N)defaultdict)IterableIteratorSized)chainteezip_longestPythonRandomInterfacePythonRandomViaNumpyBitsc                R   \        V \        \        ,          4      '       d   \        V \        4      '       d   V # Vf   . pV  FX  p\        V\        \        ,          4      '       d   \        V\        4      '       d   VP	                  V4       KM  \        W!4       KZ  	  \        V4      # )z>Return flattened version of (possibly nested) iterable object.)
isinstancer   r   strappendflattentuple)objresultitems   && Q/var/www/html/photoedit/myenv/lib/python3.14/site-packages/networkx/utils/misc.pyr   r   .   sw    c8e+,,
30D0D
~$5 011Zc5J5JMM$D!	 
 =    c                   \        V \        4      '       gL   . pV  FA  pRV 2p \        V4      pYB8w  d   \        P
                  ! T4      hTP                  T4       KC  	  V# \        V 4       FN  w  rRRV 2p\        V\        4      '       d   K"   \        V4      pYB8w  d   \        P
                  ! T4      hY@T&   KP  	  V #   \         d    \        P
                  ! T4      Rhi ; i  \         d    \        P
                  ! T4      Rhi ; i)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   make_list_of_intsr"   <   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   CC'#C$'#D
c                ^     \        W4      #   \        \        3 d    \        Y4      u # i ; i)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   dict_to_numpy_arrayr*   `   s3    1$Q00I& 1 %Q001s   
 ,,c           
        ^ RI pVfy   \        V P                  4       4      pV P                  4        F$  w  rEVP	                  VP                  4       4       K&  	  \        \        V\        \        V4      4      4      4      p\        V4      pVP                  Wf34      pVP                  4        F2  w  rVP                  4        F  w  r W,          V
,          WyV3&   K  	  K4  	  V#   \         d     K1  i ; i)zQConvert a dictionary of dictionaries to a 2d numpy array
with optional mapping.

N)numpysetkeysitemsupdatedictziprangelenzerosKeyError)r(   r)   npskvnak1r   k2js   &&          r   r$   r$   k   s    
 MGGIDAHHQVVX s1eCFm,-GA
!A]]_EB%)Q$ % ! H  s   	C&&C54C5c           
     $   ^ RI pVfA   \        V P                  4       4      p\        \	        V\        \        V4      4      4      4      p\        V4      pVP                  V4      pVP                  4        F  w  rgW,          pW,          WW&   K  	  V# )zJConvert a dictionary of numbers to a 1d numpy array with optional mapping.N)	r,   r-   r.   r1   r2   r3   r4   r5   r/   )r(   r)   r7   r8   r;   r<   r=   r   s   &&      r   r'   r'      sq    Ms1eCFm,-GA
AKu ! Hr   c                l    \        V \        4      '       d   \        R4      h\        \	        V 4      4      # )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   arbitrary_elementrE      s-    ~ (H%%KLLXr   Fc                    V'       g   \         P                  ! V 4      # \        V 4      w  r#\        VR4      p\	        V\        W434      4      # )aF  Return successive overlapping pairs taken from an input iterable.

Parameters
----------
iterable : iterable
    An iterable from which to generate pairs.

cyclic : bool, optional (default=False)
    If `True`, a pair with the last and first items is included at the end.

Returns
-------
iterator
    An iterator over successive overlapping pairs from the `iterable`.

See Also
--------
itertools.pairwise

Examples
--------
>>> list(nx.utils.pairwise([1, 2, 3, 4]))
[(1, 2), (2, 3), (3, 4)]

>>> list(nx.utils.pairwise([1, 2, 3, 4], cyclic=True))
[(1, 2), (2, 3), (3, 4), (4, 1)]
N)	itertoolspairwiser   rB   r2   r   )rD   cyclicr<   bfirsts   &&   r   rH   rH      sB    8 !!(++x=DADMEq%8$%%r   c                    \        \        4      pV P                  4        F  w  r#W,          P                  V4       K  	  \	        V4      # )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   r-   r/   addr1   )many_to_oneone_to_manyr:   r9   s   &   r   groupsrP      s>      c"K!!#1 $r   c                   ^ RI pV e   WP                  J d!   VP                  P                  P                  # \	        WP                  P
                  4      '       d   V # \	        V \        4      '       d   VP                  P                  V 4      # \	        WP                  P                  4      '       d   V # V  R2p\        V4      h)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.
NzW cannot be used to create a numpy.random.RandomState or
numpy.random.Generator instance)	r,   randommtrand_randr   RandomStater   	Generatorr   random_stater7   msgs   &  r   create_random_staterZ     s     |yy8yy%%%,		 5 566,$$yy$$\22,		 3 344. * 	*  S/r   c                   L   a  ] tR tRt o RtRR ltR tR tR tR t	R	 t
R
tV tR# )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                     ^ RI pVf'   XP
                  P                  P                  V n        MWn        RV n	        R#   \         d!    Rp\        P                  ! T\        4        Lci ; i    Nz.numpy not found, only random.random available.)
r,   ImportErrorwarningswarnImportWarningrR   rS   rT   _rng
gauss_nextselfrngr7   rY   s   &&  r   __init__!PythonRandomViaNumpyBits.__init__?  sZ    	.
 ;		((..DII   	.BCMM#}-	.s   ? (A*)A*c                6    V P                   P                  4       # )z7Get the next random number in the range 0.0 <= X < 1.0.rc   rR   rf   s   &r   rR   PythonRandomViaNumpyBits.randomO  s    yy!!r   c                    V^ 8  d   \        R4      hV^,           ^,          p\        P                  V P                  P	                  V4      R4      pW2^,          V,
          ,	          # )z:getrandbits(k) -> x.  Generates an int with k random bits.z#number of bits must be non-negativebig)r   r   
from_bytesrc   bytes)rf   r9   numbytesxs   &&  r   getrandbits$PythonRandomViaNumpyBits.getrandbitsS  sQ    q5BCCEa<NN499??84e<\A%&&r   c                6    V P                   P                  4       # N)rc   __getstate__rl   s   &r   getstate!PythonRandomViaNumpyBits.getstate[  s    yy%%''r   c                <    V P                   P                  V4       R # rw   )rc   __setstate__)rf   states   &&r   setstate!PythonRandomViaNumpyBits.setstate^  s    		u%r   c                    \        R4      h)zDo nothing override method.z2seed() not implemented in PythonRandomViaNumpyBits)NotImplementedError)rf   argskwdss   &*,r   seedPythonRandomViaNumpyBits.seeda  s    !"VWWr   )rc   rd   rw   )__name__
__module____qualname____firstlineno____doc__rh   rR   rt   ry   r~   r   __static_attributes____classdictcell____classdict__s   @r   r
   r
   -  s/     " "'(&X Xr   c                   n   a  ] tR tRt o RtRR ltR tR tRR ltR t	R	 t
R
 tR tR tR tR tRtV tR# )r	   ig  zsPythonRandomInterface is included for backward compatibility
New code should use PythonRandomViaNumpyBits instead.
Nc                     ^ RI pVf(   XP
                  P                  P                  V n        R# Wn        R#   \         d!    Rp\        P                  ! T\        4        L]i ; ir]   )	r,   r_   r`   ra   rb   rR   rS   rT   rc   re   s   &&  r   rh   PythonRandomInterface.__init__l  sQ    	.
 ;		((..DII  	.BCMM#}-	.s   9 (A$#A$c                6    V P                   P                  4       # rw   rk   rl   s   &r   rR   PythonRandomInterface.randomx  s    yy!!r   c                ^    WV,
          V P                   P                  4       ,          ,           # rw   rk   )rf   r<   rJ   s   &&&r   uniformPythonRandomInterface.uniform{  s!    ETYY--////r   c                >   ^ RI pVf   ^ Tr!VR8  d'   \        V P                  4      pVP                  W4      # \	        V P                  VP
                  P                  4      '       d   V P                  P                  W4      # V P                  P                  W4      # r^   Nl    )	r,   r
   rc   	randranger   rR   rV   integersrandintrf   r<   rJ   r7   tmp_rngs   &&&  r   r   PythonRandomInterface.randrange~  s~    9aq"".tyy9G$$Q**dii!4!45599%%a++yy  &&r   c                   ^ RI p\        V P                  VP                  P                  4      '       d.   V P                  P                  ^ \        V4      4      pW,          # V P                  P                  ^ \        V4      4      pW,          # )r^   N)r,   r   rc   rR   rV   r   r4   r   )rf   seqr7   idxs   &&  r   choicePythonRandomInterface.choice  sf    dii!4!455))$$QC1C x ))##As3x0Cxr   c                8    V P                   P                  W4      # rw   )rc   normal)rf   musigmas   &&&r   gaussPythonRandomInterface.gauss  s    yy**r   c                8    V P                   P                  V4      # rw   )rc   shuffle)rf   r   s   &&r   r   PythonRandomInterface.shuffle  s    yy  %%r   c                R    V P                   P                  \        V4      V3R R7      # )F)sizereplace)rc   r   r   )rf   r   r9   s   &&&r   samplePythonRandomInterface.sample  s$    yyS	eDDr   c                L   ^ RI pVR8  d'   \        V P                  4      pVP                  W4      # \	        V P                  VP
                  P                  4      '       d#   V P                  P                  W^,           4      # V P                  P                  W^,           4      # r   )r,   r
   rc   r   r   rR   rV   r   r   s   &&&  r   r   PythonRandomInterface.randint  sx    "".tyy9G??1((dii!4!45599%%aQ//yy  E**r   c                F    V P                   P                  ^V,          4      # )   )rc   exponential)rf   scales   &&r   expovariate!PythonRandomInterface.expovariate  s    yy$$QY//r   c                8    V P                   P                  V4      # rw   )rc   pareto)rf   shapes   &&r   paretovariate#PythonRandomInterface.paretovariate  s    yy&&r   )rc   rw   )r   r   r   r   r   rh   rR   r   r   r   r   r   r   r   r   r   r   r   r   s   @r   r	   r	   g  sG     
"0'+&E	+0' 'r   c                   V e   V \         J d   \         P                  # \        V \         P                  4      '       d   V # \        V \        4      '       d   \         P                  ! V 4      #  ^ RIp\        V \        \        ,          4      '       d   V # \        WP                   P                  4      '       d   \        V 4      # WP                   J d*   \        VP                   P                  P                  4      # \        WP                   P                  4      '       d:   WP                   P                  P                  J d   \        V 4      # \        V 4      #  V  R2p\        V4      h  \         d     Li ; i)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.
Nz4 cannot be used to generate a random.Random instance)rR   _instr   Randomr   r,   r	   r
   rV   rS   rT   rU   r_   r   rW   s   &  r   create_py_random_stater     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:9E:c                    \        V 4      p\        V4      p \        V4      p\        V4      pWE8H  #   \        \        3 d1    \        P	                  T4      p\        P	                  T4      p YE8H  # i ; i)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   r1   r   r&   fromkeys)nodes1nodes2nlist1nlist2d1d2s   &&    r   nodes_equalr     so      &\F&\F#&\&\ 8O 	" #]]6"]]6"8O#s   2 ;A32A3directedc                 a
a \        \        4      o
\        \        4      o\        WRR7       Fa  w  r4Ve   Vf    R# VS
3VS33 FE  w  rVVvrxp	WgV3,          P                  V	4       V'       d   K,  WhV3,          P                  V	4       KG  	  Kc  	  \        ;QJ d     V
V3R lS
 4       F  '       d   K   R# 	  R# ! V
V3R lS
 4       4      # )a  Return whether edgelists are equal.

Equality here means equal as Python objects. Edge data must match
if included. Ordering of edges in an edgelist is not relevant;
ordering of nodes in an edge is only relevant if ``directed == True``.

Parameters
----------
edges1, edges2 : iterables of tuples
    Each tuple can be
    an edge tuple ``(u, v)``, or
    an edge tuple with data `dict` s ``(u, v, d)``, or
    an edge tuple with keys and data `dict` s ``(u, v, k, d)``.

directed : bool, optional (default=False)
    If `True`, edgelists are treated as coming from directed
    graphs.

Returns
-------
bool
    `True` if edgelists are equal, `False` otherwise.

Examples
--------
>>> G1 = nx.complete_graph(3)
>>> G2 = nx.cycle_graph(3)
>>> edges_equal(G1.edges, G2.edges)
True

Edge order is not taken into account:

>>> G1 = nx.Graph([(0, 1), (1, 2)])
>>> G2 = nx.Graph([(1, 2), (0, 1)])
>>> edges_equal(G1.edges, G2.edges)
True

The `directed` parameter controls whether edges are treated as
coming from directed graphs.

>>> DG1 = nx.DiGraph([(0, 1)])
>>> DG2 = nx.DiGraph([(1, 0)])
>>> edges_equal(DG1.edges, DG2.edges, directed=False)  # Not recommended.
True
>>> edges_equal(DG1.edges, DG2.edges, directed=True)
False

This function is meant to be used on edgelists (i.e. the output of a
``G.edges()`` call), and can give unexpected results on unprocessed
lists of edges:

>>> l1 = [(0, 1)]
>>> l2 = [(0, 1), (1, 0)]
>>> edges_equal(l1, l2)  # Not recommended.
False
>>> G1 = nx.Graph(l1)
>>> G2 = nx.Graph(l2)
>>> edges_equal(G1.edges, G2.edges)
True
>>> DG1 = nx.DiGraph(l1)
>>> DG2 = nx.DiGraph(l2)
>>> edges_equal(DG1.edges, DG2.edges, directed=True)
False
N)	fillvalueFc              3      <"   T FF  pSV,           F6  pSV,          P                  V4      SV,          P                  V4      8H  x  K8  	  KH  	  R # 5irw   )count).0edatar   r   s   &  r   	<genexpr>edges_equal.<locals>.<genexpr>l  s@     Tr!bQReedr!u{{4 BqEKK$55e5rs   AAT)r   r   r   r   all)edges1edges2r   e1e2r   r(   ur:   r   r   r   s   &&$       @@r   edges_equalr     s    B 
T	B	T	Bf=:"XBx(DAKA4dGNN4 8Q$t$	 ) > 3TrT33T3T3TrTTTr   c                    V P                   VP                   8H  ;'       d;    V P                  VP                  8H  ;'       d    V P                  VP                  8H  # )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   graphs_equalr   o  sM      	

fjj  	) 	)LLFLL(	) 	)LLFLL(r   c                T    \        V RR4      ;p'       d   VP                  4        R# R# )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   _clear_cacher     s'    
 /66u6 7r   
multigraphdefaultc               Z   Vf   \         P                  pV e   T MTp\        V\        4      '       d   VP	                  R4      MVP	                  4       p\        V\        4      '       d   VP                  R4      MVP                  4       pVeM   V'       d   V'       g   \         P                  ! R4      hV'       g   V'       d   \         P                  ! R4      hVeM   V'       d   V'       g   \         P                  ! R4      hV'       g   V'       d   \         P                  ! R4      hV# )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   r"   r*   rE   rH   rP   rZ   r   r	   r
   r   r   r   r   rw   )F)"r   rG   rR   r`   collectionsr   collections.abcr   r   r   r   r   r   networkxr   __all__r   r"   r*   r$   r'   rE   rH   rP   rZ   r   r
   r	   r   r   r   r   r   r    r   r   <module>r      s       # 5 5 - - .!H1.B J &F,<6Xv}} 6XtL' L't?D6NUE NUb,1 1$ 1PT 1r   