ó
    †~i<Y  ã                   ó,  • S r SSKrSSKrSSKrSSKJr  SSKJrJrJ	r	  SSKJ
r
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\R2                  5      r " S S5      rSS jrS rSS.S j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 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)Ú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      ÚP/home/mande/repo/quber/.venv/lib/python3.13/site-packages/networkx/utils/misc.pyr
   r
   .   sw   € ä�cœ8¤eÑ+×,Ñ,´
¸3Ä×0DÑ0DØˆ
Ø�~ØˆÛˆÜ˜$¤¬5Ñ 0×1Ñ1´ZÀÄc×5JÑ5JØ�M‰M˜$Öä�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Ø5°a°SÐ9ˆFð9Ü˜“V�ð ‹wÜ×&Ò& vÓ.Ð.Ø�M‰M˜"Öñ ð ˆä˜XÖ&‰ˆØ1°!°Ð5ˆÜ�aœ×ÑÙð	5Ü�Q“ˆBð ‹7Ü×"Ò" 6Ó*Ð*Ø�‹ñ 'ð €Oøô% ó 9Ü×&Ò& vÓ.°DÐ8ð9ûô ó 	5Ü×"Ò" 6Ó*°Ð4ð	5ús   £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   `   s3   € ð1Ü$ QÓ0Ð0øÜœIÐ&ó 1ô % QÓ0Ò0ð1ús   ‚
 �+ª+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  p‰U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/   k   sÆ   € ó
 à�Ü�—‘“‹MˆØ—G‘G–I‰DˆAØ�H‰H�Q—V‘V“XÖñ ä”s˜1œe¤C¨£F›mÓ,Ó-ˆÜˆG‹€AØ
�‰�!�Ó€AØ—‘–‰ˆØ—]‘]–_‰EˆBðØ™% ™)��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ˆÜ”s˜1œe¤C¨£F›mÓ,Ó-ˆÜˆ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!   Fc                 óš   • U(       d  [         R                  " U 5      $ [        U 5      u  p#[        US5      n[	        U[        X445      5      $ )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)Ú	itertoolsr   r   rL   r<   r   )rN   ÚcyclicrF   ÚbÚfirsts        r    r   r   Ö   sB   € ö8 Ü×!Ò! (Ó+Ð+Üˆx‹=�D€AÜ��D‹M€EÜˆq”%˜˜8Ó$Ó%Ð%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¤   € ó àÑ˜|¯y©yÒ8Ø�y‰y×Ñ×%Ñ%Ð%Ü�,§	¡	× 5Ñ 5×6Ñ6ØÐÜ�,¤×$Ñ$Ø�y‰y×$Ñ$ \Ó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ÚImportWarningrY   rZ   r[   Ú_rngÚ
gauss_next©ÚselfÚrngrA   r`   s       r    Ú__init__Ú!PythonRandomViaNumpyBits.__init__?  sZ   € ð	.Ûð
 ‰;ØŸ	™	×(Ñ(×.Ñ.ˆD�IàŒIð ˆ�øô ó 	.ØBˆCÜ�MŠM˜#œ}Ö-ð	.ús   ‚= ½'A'Á&A'c                 ó6   • U R                   R                  5       $ )z7Get the next random number in the range 0.0 <= X < 1.0.©rh   rY   ©rk   s    r    rY   ÚPythonRandomViaNumpyBits.randomO  s   € à�y‰y×ÑÓ!Ð!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_bytesrh   Úbytes)rk   rC   ÚnumbytesÚxs       r    ÚgetrandbitsÚ$PythonRandomViaNumpyBits.getrandbitsS  sQ   € àˆq‹5ÜÐBÓCÐCØ˜‘E˜a‘<ˆÜ�N‰N˜4Ÿ9™9Ÿ?™?¨8Ó4°eÓ<ˆØ ‘\ AÑ%Ñ&Ð&r!   c                 ó6   • U R                   R                  5       $ ©N)rh   Ú__getstate__rq   s    r    ÚgetstateÚ!PythonRandomViaNumpyBits.getstate[  s   € Ø�y‰y×%Ñ%Ó'Ð'r!   c                 ó:   • U R                   R                  U5        g r~   )rh   Ú__setstate__)rk   Ústates     r    ÚsetstateÚ!PythonRandomViaNumpyBits.setstate^  s   € Ø�	‰	×Ñ˜uÕ%r!   c                 ó   • [        S5      e)zDo nothing override method.z2seed() not implemented in PythonRandomViaNumpyBits)ÚNotImplementedError)rk   ÚargsÚkwdss      r    ÚseedÚPythonRandomViaNumpyBits.seeda  s   € ä!Ð"VÓWÐWr!   )rh   ri   r~   )Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__rm   rY   r{   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   ig  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rc   )	r6   rd   re   rf   rg   rY   rZ   r[   rh   rj   s       r    rm   ÚPythonRandomInterface.__init__l  sQ   € ð	.Ûð
 ‰;ØŸ	™	×(Ñ(×.Ñ.ˆD�Ià�Iøô ó 	.ØBˆCÜ�MŠM˜#œ}Ö-ð	.ús   ‚6 ¶'A ÁA c                 ó6   • U R                   R                  5       $ r~   rp   rq   s    r    rY   ÚPythonRandomInterface.randomx  s   € Ø�y‰y×ÑÓ!Ð!r!   c                 óF   • XU-
  U R                   R                  5       -  -   $ r~   rp   )rk   rF   rR   s      r    ÚuniformÚPythonRandomInterface.uniform{  s!   € Ø˜‘E˜TŸY™Y×-Ñ-Ó/Ñ/Ñ/Ð/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   rh   Ú	randranger   rY   r]   ÚintegersÚrandint©rk   rF   rR   rA   Útmp_rngs        r    rž   ÚPythonRandomInterface.randrange~  s~   € Ûà‰9Ø�aˆqØÐ"Ó"Ü.¨t¯y©yÓ9ˆGØ×$Ñ$ QÓ*Ð*ä�d—i‘i §¡×!4Ñ!4×5Ñ5Ø—9‘9×%Ñ% aÓ+Ð+Ø�y‰y× Ñ  Ó&Ð&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   rh   rY   r]   rŸ   r>   r    )rk   ÚseqrA   Úidxs       r    ÚchoiceÚPythonRandomInterface.choice�  sf   € Ûä�d—i‘i §¡×!4Ñ!4×5Ñ5Ø—)‘)×$Ñ$ Q¬¨C«Ó1ˆCð ‰xˆð —)‘)×#Ñ# A¤s¨3£xÓ0ˆCØ‰xˆr!   c                 ó8   • U R                   R                  X5      $ r~   )rh   Únormal)rk   ÚmuÚsigmas      r    ÚgaussÚPythonRandomInterface.gauss–  s   € Ø�y‰y×Ñ Ó*Ð*r!   c                 ó8   • U R                   R                  U5      $ r~   )rh   Úshuffle)rk   r¥   s     r    r°   ÚPythonRandomInterface.shuffle™  s   € Ø�y‰y× Ñ  Ó%Ð%r!   c                 óL   • U R                   R                  [        U5      U4SS9$ )NF)ÚsizeÚreplace)rh   r§   r#   )rk   r¥   rC   s      r    ÚsampleÚPythonRandomInterface.sampleŸ  s$   € Ø�y‰y×Ñ¤ 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   rh   r    r   rY   r]   rŸ   r¡   s        r    r    ÚPythonRandomInterface.randint¢  sx   € ÛàÐ"Ó"Ü.¨t¯y©yÓ9ˆGØ—?‘? 1Ó(Ð(ä�d—i‘i §¡×!4Ñ!4×5Ñ5Ø—9‘9×%Ñ% a¨Q©Ó/Ð/Ø�y‰y× Ñ  ¨¡EÓ*Ð*r!   c                 ó>   • U R                   R                  SU-  5      $ )Nr¸   )rh   Úexponential)rk   Úscales     r    ÚexpovariateÚ!PythonRandomInterface.expovariate®  s   € Ø�y‰y×$Ñ$ Q¨¡YÓ/Ð/r!   c                 ó8   • U R                   R                  U5      $ r~   )rh   Úpareto)rk   Úshapes     r    ÚparetovariateÚ#PythonRandomInterface.paretovariate²  s   € Ø�y‰y×Ñ Ó&Ð&r!   )rh   r~   )r�   rŽ   r�   r�   r‘   rm   rY   rš   rž   r§   r­   r°   rµ   r    r½   rÂ   r’   r“   r!   r    r   r   g  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)rY   Ú_instr   ÚRandomr$   r6   r   r   r]   rZ   r[   r\   rd   r%   r^   s      r    r   r   Á  s+  € ðJ Ñ˜|¬vÒ5Ü�|‰|ÐÜ�,¤§¡×.Ñ.ØÐÜ�,¤×$Ñ$Ü�}Š}˜\Ó*Ð*ð7Ûô �lÔ$9Ô<TÑ$T×UÑUØÐÜ�l§I¡I×$7Ñ$7×8Ñ8Ü+¨LÓ9Ð9ØŸ9™9Ò$Ü+¨B¯I©I×,<Ñ,<×,BÑ,BÓCÐCä�l§I¡I×$9Ñ$9×:Ñ:ØŸy™y×/Ñ/×5Ñ5Ò5Ü/°Ó=Ð=ä(¨Ó6Ð6ð	 ;ð ˆNÐNÐ
O€CÜ
�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ð#Ü�&‹\ˆÜ�&‹\ˆð ‰8€Oøô œ	Ð"ó #Ü�]‰]˜6Ó"ˆÜ�]‰]˜6Ó"‰Ø‰8€Oð#ús   ˜2 ²:A2Á1A2)Údirectedc                ó4  ^
^• [        [        5      m
[        [        5      m[        XSS9 HU  u  p4Ub  Uc    gUT
4UT44 H<  u  pVUtpxn	XgU4   R                  U	5        U(       a  M'  XhU4   R                  U	5        M>     MW     [	        U
U4S jT
 5       5      $ )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   ó�   >#   • U  H;  nTU     H.  nTU   R                  U5      TU   R                  U5      :H  v •  M0     M=     g 7fr~   )Úcount)Ú.0ÚeÚdatarÍ   rÎ   s      €€r    Ú	<genexpr>Úedges_equal.<locals>.<genexpr>l  s>   øé € ÐTºr¸!ÈbÐQRÍeÀdˆr�!‰u�{‰{˜4Ó  B q¡E§K¡K°Ó$5Ö5ÉeÑ5ºrùs   ƒAA)r   r#   r	   r   Úall)Úedges1Úedges2rÏ   Úe1Úe2rÕ   r3   ÚurD   rÖ   rÍ   rÎ   s             @@r    r   r     s—   ù€ ôB 
”TÓ	€BÜ	”TÓ	€Bä˜f¸Ô=‰ˆØ‰:˜™ÙØ˜"�X  B˜xÓ(‰DˆAØˆKˆA�4Ø�ˆd‰G�N‰N˜4Ô ß�8Ø�Q�$‘—‘˜tÖ$ó	 )ñ >ô ÕT¹rÓTÓTÐTr!   c                 ó´   • U R                   UR                   :H  =(       a9    U R                  UR                  :H  =(       a    U R                  UR                  :H  $ )zô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   o  sC   € ð  	�
‰
�f—j‘jÑ ÷ 	)Ø�L‰L˜FŸL™LÑ(÷	)à�L‰L˜FŸL™LÑ(ðr!   c                 óN   • [        U SS5      =n(       a  UR                  5         gg)z�Clear 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'   € ô
 ˜Ð/°Ó6Ð6€uÕ6Ø�‰�ð 7r!   )rÏ   Ú
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‰°g€Aä(2°1´d×(;Ñ(;�—‘˜tÔ$ÀÇÁÃ€JÜ,6°q¼$×,?Ñ,?�1—?‘? 4Ô(ÀQÇ_Á_ÓEV€LàÑÞžJÜ×"Ò"Ð#BÓCÐCÞžJÜ×"Ò"Ð#FÓGÐGàÑÞžlÜ×"Ò"Ð#GÓHÐHÞžlÜ×"Ò"Ð#KÓLÐLØ€Hr!   r~   )F)"r‘   rP   rY   re   Úcollectionsr   Úcollections.abcr   r   r   r   r   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 ôJ &òFô,ô<6X˜vŸ}™}ô 6X÷tL'ñ L'ôt?òDð6 -2õ NUòbò,ð 26À$ÐPTö 1r!   