Ë
    ÷Ç:j<Y  ã                   ó  — d Z ddlZddlZddlZddlmZ ddlmZmZm	Z	 ddlm
Z
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j2                  «      Z G d„ d«      Zdd„Zd„ Zddœ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 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                 ó
  — 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      úh/home/mcse/projects/srt_converter/srt-converter-venv/lib/python3.12/site-packages/networkx/utils/misc.pyr
   r
   .   sr   € ä�cœ8¤eÑ+Ô,´
¸3ÄÔ0DØˆ
Ø€~ØˆØò "ˆÜ˜$¤¬5Ñ 0Ô1´ZÀÄcÔ5JØ�M‰M˜$Õä�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Ø5°a°SÐ9ˆFð9Ü˜“V�ð �QŠwÜ×&Ñ& vÓ.Ð.Ø�M‰M˜"Õð	ð ˆä˜XÓ&ò 
‰ˆˆaØ1°!°Ð5ˆÜ�aœÔØð	5Ü�Q“ˆBð �Š7Ü×"Ñ" 6Ó*Ð*Øˆ�Šð
ð €Oøô% ò 9Ü×&Ñ& vÓ.°DÐ8ð9ûô ò 	5Ü×"Ñ" 6Ó*°Ð4ð	5ús   ž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   `   s7   € ð1Ü$ Q¨Ó0Ð0øÜœIÐ&ò 1ô % Q¨Ó0Ò0ð1ús   ‚ Ž,«,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/   k   sá   € ó
 à€Ü�—‘“‹MˆØ—G‘G“Iò 	‰DˆAˆqØ�H‰H�Q—V‘V“XÕð	ä”s˜1œe¤C¨£F›mÓ,Ó-ˆÜˆG‹€AØ
�‰�!�Q�Ó€AØ—‘“ò ‰ˆˆAØ—]‘]“_ò 	‰EˆB�ðØ˜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ˆÜ”s˜1œe¤C¨£F›mÓ,Ó-ˆÜˆG‹€AØ
�‰�‹€AØ—‘“ò ‰ˆˆAØ�B‰KˆØ�‰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!   Fc                 ó’   — |st        j                  | «      S t        | «      \  }}t        |d«      }t	        |t        ||f«      «      S )a–  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   Ö   sF   € ñ8 Ü×!Ñ! (Ó+Ð+Üˆx‹=�D€A€qÜ��D‹M€EÜˆq”%˜˜E˜8Ó$Ó%Ð%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¡   € ó àÐ˜|¨r¯y©yÑ8Ø�y‰y×Ñ×%Ñ%Ð%Ü�, §	¡	× 5Ñ 5Ô6ØÐÜ�,¤Ô$Ø�y‰y×$Ñ$ \Ó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ÚImportWarningrY   rZ   r[   Ú_rngÚ
gauss_next©ÚselfÚrngrA   r`   s       r    Ú__init__z!PythonRandomViaNumpyBits.__init__?  sg   € ð	.Ûð
 ˆ;ØŸ	™	×(Ñ(×.Ñ.ˆDŒIð ˆ�ð	 ˆDŒIð ˆ�øô ò 	.ØBˆCÜ�M‰M˜#œ}Ö-ð	.ús   ‚A Á%A,Á+A,c                 ó6   — | j                   j                  «       S )z7Get the next random number in the range 0.0 <= X < 1.0.©rh   rY   ©rk   s    r    rY   zPythonRandomViaNumpyBits.randomO  s   € à�y‰y×ÑÓ!Ð!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_bytesrh   Úbytes)rk   rC   ÚnumbytesÚxs       r    Úgetrandbitsz$PythonRandomViaNumpyBits.getrandbitsS  sS   € àˆqŠ5ÜÐBÓCÐCØ˜‘E˜a‘<ˆÜ�N‰N˜4Ÿ9™9Ÿ?™?¨8Ó4°eÓ<ˆØ�X ‘\ AÑ%Ñ&Ð&r!   c                 ó6   — | j                   j                  «       S ©N)rh   Ú__getstate__rp   s    r    Úgetstatez!PythonRandomViaNumpyBits.getstate[  s   € Ø�y‰y×%Ñ%Ó'Ð'r!   c                 ó:   — | j                   j                  |«       y r{   )rh   Ú__setstate__)rk   Ústates     r    Úsetstatez!PythonRandomViaNumpyBits.setstate^  s   € Ø�	‰	×Ñ˜uÕ%r!   c                 ó   — t        d«      ‚)zDo nothing override method.z2seed() not implemented in PythonRandomViaNumpyBits)ÚNotImplementedError)rk   ÚargsÚkwdss      r    ÚseedzPythonRandomViaNumpyBits.seeda  s   € ä!Ð"VÓWÐWr!   r{   )
Ú__name__Ú
__module__Ú__qualname__Ú__doc__rm   rY   ry   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rc   )	r6   rd   re   rf   rg   rY   rZ   r[   rh   rj   s       r    rm   zPythonRandomInterface.__init__l  sS   € ð	.Ûð
 ˆ;ØŸ	™	×(Ñ(×.Ñ.ˆD�IàˆD�Iøô ò 	.ØBˆCÜ�M‰M˜#œ}Ö-ð	.ús   ‚6 ¶%AÁAc                 ó6   — | j                   j                  «       S r{   ro   rp   s    r    rY   zPythonRandomInterface.randomx  s   € Ø�y‰y×ÑÓ!Ð!r!   c                 óH   — |||z
  | j                   j                  «       z  z   S r{   ro   )rk   rF   rR   s      r    ÚuniformzPythonRandomInterface.uniform{  s#   € Ø�A˜‘E˜TŸY™Y×-Ñ-Ó/Ñ/Ñ/Ð/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   rh   Ú	randranger   rY   r]   ÚintegersÚrandint©rk   rF   rR   rA   Útmp_rngs        r    r“   zPythonRandomInterface.randrange~  sƒ   € Ûàˆ9Ø�aˆqˆAØÐ"Ò"Ü.¨t¯y©yÓ9ˆGØ×$Ñ$ Q¨Ó*Ð*ä�d—i‘i §¡×!4Ñ!4Ô5Ø—9‘9×%Ñ% a¨Ó+Ð+Ø�y‰y× Ñ   AÓ&Ð&r!   c                 ó  — dd l }t        | j                  |j                  j                  «      r*| j                  j                  dt        |«      «      }||   S | j                  j                  dt        |«      «      }||   S )Nr   )r6   r   rh   rY   r]   r”   r>   r•   )rk   ÚseqrA   Úidxs       r    ÚchoicezPythonRandomInterface.choice�  sg   € Ûä�d—i‘i §¡×!4Ñ!4Ô5Ø—)‘)×$Ñ$ Q¬¨C«Ó1ˆCð �3‰xˆð —)‘)×#Ñ# A¤s¨3£xÓ0ˆCØ�3‰xˆr!   c                 ó:   — | j                   j                  ||«      S r{   )rh   Únormal)rk   ÚmuÚsigmas      r    ÚgausszPythonRandomInterface.gauss–  s   € Ø�y‰y×Ñ  EÓ*Ð*r!   c                 ó8   — | j                   j                  |«      S r{   )rh   Úshuffle)rk   r™   s     r    r¢   zPythonRandomInterface.shuffle™  s   € Ø�y‰y× Ñ  Ó%Ð%r!   c                 óR   — | j                   j                  t        |«      |fd¬«      S )NF)ÚsizeÚreplace)rh   r›   r#   )rk   r™   rC   s      r    ÚsamplezPythonRandomInterface.sampleŸ  s$   € Ø�y‰y×Ñ¤ 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   rh   r•   r   rY   r]   r”   r–   s        r    r•   zPythonRandomInterface.randint¢  s{   € ÛàÐ"Ò"Ü.¨t¯y©yÓ9ˆGØ—?‘? 1 aÓ(Ð(ä�d—i‘i §¡×!4Ñ!4Ô5Ø—9‘9×%Ñ% a¨¨Q©Ó/Ð/Ø�y‰y× Ñ   A¨¡EÓ*Ð*r!   c                 ó>   — | j                   j                  d|z  «      S )Nr¨   )rh   Úexponential)rk   Úscales     r    Úexpovariatez!PythonRandomInterface.expovariate®  s   € Ø�y‰y×$Ñ$ Q¨¡YÓ/Ð/r!   c                 ó8   — | j                   j                  |«      S r{   )rh   Úpareto)rk   Úshapes     r    Úparetovariatez#PythonRandomInterface.paretovariate²  s   € Ø�y‰y×Ñ Ó&Ð&r!   r{   )r‡   rˆ   r‰   rŠ   rm   rY   r�   r“   r›   r    r¢   r¦   r•   r¬   r°   r‹   r!   r    r   r   g  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)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ØÐÜ�l B§I¡I×$7Ñ$7Ô8Ü+¨LÓ9Ð9Ø˜2Ÿ9™9Ñ$Ü+¨B¯I©I×,<Ñ,<×,BÑ,BÓCÐCä�l B§I¡I×$9Ñ$9Ô:Ø˜rŸy™y×/Ñ/×5Ñ5Ñ5Ü/°Ó=Ð=ä(¨Ó6Ð6àˆNÐNÐ
O€CÜ
�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ð#Ü�&‹\ˆÜ�&‹\ˆð �‰8€Oøô œ	Ð"ò #Ü�]‰]˜6Ó"ˆÜ�]‰]˜6Ó"‰Ø�‰8€Oð#ús   ˜3 ³9A3Á2A3)Údirectedc                ó,  ‡
‡— t        t        «      Š
t        t        «      Št        | |d¬«      D ]O  \  }}|�|€ y|‰
f|‰ffD ]9  \  }}|^}}}	|||f   j                  |	«       |rŒ$|||f   j                  |	«       Œ; ŒQ t	        ˆ
ˆfd„‰
D «       «      S )aV  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   ó„   •K  — | ]7  }‰|   D ]-  }‰|   j                  |«      ‰|   j                  |«      k(  –— Œ/ Œ9 y ­wr{   )Úcount)Ú.0ÚeÚdatarº   r»   s      €€r    ú	<genexpr>zedges_equal.<locals>.<genexpr>l  sB   øè ø€ ÒT¸!ÈbÐQRÉeÒTÀdˆr�!‰u�{‰{˜4Ó  B q¡E§K¡K°Ó$5Õ5ÐTÐ5ÑTùs   ƒ=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 f¸Ô=ò %‰ˆˆBØˆ:˜˜ÙØ˜"�X  B˜xÐ(ò 	%‰DˆAˆqØˆKˆAˆq�4Øˆa�ˆd‰G�N‰N˜4Ô ÚØ�!�Q�$‘—‘˜tÕ$ñ		%ð%ô ÔT¸rÔTÓTÐTr!   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   o  sC   € ð  	�
‰
�f—j‘jÑ ò 	)Ø�L‰L˜FŸL™LÑ(ò	)à�L‰L˜FŸL™LÑ(ðr!   c                 óD   — t        | dd«      x}r|j                  «        yy)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                óÊ  — |€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‰°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!   