
    k
qi<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j                  Z G d d          ZddZd ZdddZd Zd Z dddddZ!dS )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                 J   t          | t          t          z            rt          | t                    r| S |g }| D ]Z}t          |t          t          z            rt          |t                    r|                    |           Jt          ||           [t          |          S )z>Return flattened version of (possibly nested) iterable object.)
isinstancer   r   strappendr
   tuple)objresultitems      s/var/www/html/bestrading.cuttalo.com/services/ml-inference/venv/lib/python3.11/site-packages/networkx/utils/misc.pyr
   r
   .   s    c8e+,, 
30D0D 
~ " "$5 011 	"Zc5J5J 	"MM$D&!!!!==    c                    t          | t                    sqg }| D ]j}d| }	 t          |          }n## t          $ r t	          j        |          dw xY w||k    rt	          j        |          |                    |           k|S t          |           D ]s\  }}d| }t          |t                    r 	 t          |          }n## t          $ r t	          j        |          dw xY w||k    rt	          j        |          || |<   t| S )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   <   sR    h%%  	 	A9a99F9VV 9 9 9&v..D89Qww&v...MM"X&& 
 
a5!55a 		5QBB 	5 	5 	5"6**4	577"6***Os   2 A7C C'c                 r    	 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   `   sO    1$Q000I& 1 1 1 %Q000001s    !66c           
      @   ddl }|t          |                                           }|                                 D ],\  }}|                    |                                           -t          t          |t          t          |                                        }t          |          }|	                    ||f          }|                                D ]C\  }}	|                                D ])\  }
}	 | |         |
         ||	|f<   # t          $ r Y &w xY wD|S )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!   
 MMGGII 	 	DAqHHQVVXXs1eCFFmm,,--GA
!QA  A]]__ 	 	EBB%)!Q$   	
 Hs   9D
DDc           
      d   ddl }|Xt          |                                           }t          t	          |t          t          |                                        }t          |          }|                    |          }|                                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    MMs1eCFFmm,,--GA
A  ABKu!Hr!   c                     t          | t                    rt          d          t          t	          |                     S )a  Returns an arbitrary element of `iterable` without removing it.

    This is most useful for "peeking" at an arbitrary element of a set,
    but can be used for any list, dictionary, etc., as well.

    Parameters
    ----------
    iterable : `abc.collections.Iterable` instance
        Any object that implements ``__iter__``, e.g. set, dict, list, tuple,
        etc.

    Returns
    -------
    The object that results from ``next(iter(iterable))``

    Raises
    ------
    ValueError
        If `iterable` is an iterator (because the current implementation of
        this function would consume an element from the iterator).

    Examples
    --------
    Arbitrary elements from common Iterable objects:

    >>> nx.utils.arbitrary_element([1, 2, 3])  # list
    1
    >>> nx.utils.arbitrary_element((1, 2, 3))  # tuple
    1
    >>> nx.utils.arbitrary_element({1, 2, 3})  # set
    1
    >>> d = {k: v for k, v in zip([1, 2, 3], [3, 2, 1])}
    >>> nx.utils.arbitrary_element(d)  # dict_keys
    1
    >>> nx.utils.arbitrary_element(d.values())  # dict values
    3

    `str` is also an Iterable:

    >>> nx.utils.arbitrary_element("hello")
    'h'

    :exc:`ValueError` is raised if `iterable` is an iterator:

    >>> iterator = iter([1, 2, 3])  # Iterator, *not* Iterable
    >>> nx.utils.arbitrary_element(iterator)
    Traceback (most recent call last):
        ...
    ValueError: cannot return an arbitrary item from an iterator

    Notes
    -----
    This function does not return a *random* element. If `iterable` is
    ordered, sequential calls will return the same value::

        >>> l = [1, 2, 3]
        >>> nx.utils.arbitrary_element(l)
        1
        >>> nx.utils.arbitrary_element(l)
        1

    z0cannot return an arbitrary item from an iterator)r   r   r%   nextiter)iterables    r    r   r      s;    ~ (H%% MKL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      sU    8  ,!(+++x==DAqDMMEq%E8$$%%%r!   c                     t          t                    }|                                 D ] \  }}||                             |           !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      sY      c""K!!##  1A1r!   c                 8   ddl }| 	| |j        u r|j        j        j        S t	          | |j        j                  r| S t	          | t                    r|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     |ry88y%%,	 566 ,$$ 3y$$\222,	 344  	* 	* 	*  S//r!   c                   8    e Zd ZdZd	dZd Zd Zd Zd Zd Z	dS )
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 }n,# t          $ r d}t          j        |t                     Y nw xY w||j        j        j        | _        n|| _        d | _	        d S 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__?  sz    	. 	. 	. 	.BCM#}-----	. ;	(.DIIDI     &00c                 4    | 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!!!r!   c                     |dk     rt          d          |dz   dz  }t                              | 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  s\    q55BCCCEa<NN49??844e<<X\A%&&r!   c                 4    | j                                         S N)rh   __getstate__rq   s    r    getstatez!PythonRandomViaNumpyBits.getstate[  s    y%%'''r!   c                 :    | j                             |           d S 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WWr!   r|   )
__name__
__module____qualname____doc__rm   rY   rz   r~   r   r    r!   r    r   r   -  s         "    " " "' ' '( ( (& & &X X X X Xr!   r   c                   X    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dS )r   z{PythonRandomInterface is included for backward compatibility
    New code should use PythonRandomViaNumpyBits instead.
    Nc                     	 dd l }n,# t          $ r d}t          j        |t                     Y nw xY w||j        j        j        | _        d S || _        d S rc   )	r6   rd   re   rf   rg   rY   rZ   r[   rh   rj   s       r    rm   zPythonRandomInterface.__init__l  ss    	. 	. 	. 	.BCM#}-----	. ;	(.DIIIDIIIrn   c                 4    | j                                         S r|   rp   rq   s    r    rY   zPythonRandomInterface.randomx  s    y!!!r!   c                 F    |||z
  | j                                         z  z   S r|   rp   )rk   rF   rR   s      r    uniformzPythonRandomInterface.uniform{  s$    AETY--/////r!   c                     dd l }|d|}}|dk    r*t          | j                  }|                    ||          S t	          | j        |j        j                  r| j                            ||          S | j                            ||          S )Nr       )	r6   r   rh   	randranger   rY   r]   integersrandintrk   rF   rR   rA   tmp_rngs        r    r   zPythonRandomInterface.randrange~  s    9aqA""".ty99G$$Q***di!455 	,9%%a+++y  A&&&r!   c                     dd l }t          | j        |j        j                  r)| j                            dt          |                    }n(| j                            dt          |                    }||         S )Nr   )r6   r   rh   rY   r]   r   r>   r   )rk   seqrA   idxs       r    choicezPythonRandomInterface.choice  sl    di!455 	1)$$QC11CC)##As3xx00C3xr!   c                 8    | j                             ||          S r|   )rh   normal)rk   musigmas      r    gausszPythonRandomInterface.gauss  s    yE***r!   c                 6    | j                             |          S r|   )rh   shuffle)rk   r   s     r    r   zPythonRandomInterface.shuffle  s    y  %%%r!   c                 X    | j                             t          |          |fd          S )NF)sizereplace)rh   r   r#   )rk   r   rC   s      r    samplezPythonRandomInterface.sample  s'    yS		eDDDr!   c                     dd l }|dk    r*t          | j                  }|                    ||          S t	          | j        |j        j                  r| j                            ||dz             S | j                            ||dz             S )Nr   r      )r6   r   rh   r   r   rY   r]   r   r   s        r    r   zPythonRandomInterface.randint  s    """.ty99G??1a(((di!455 	09%%aQ///y  AE***r!   c                 <    | j                             d|z            S )Nr   )rh   exponential)rk   scales     r    expovariatez!PythonRandomInterface.expovariate  s    y$$QY///r!   c                 6    | j                             |          S r|   )rh   pareto)rk   shapes     r    paretovariatez#PythonRandomInterface.paretovariate  s    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 0 0' ' ' '  + + +& & &E E E	+ 	+ 	+0 0 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                  r1| |j         j	        j
        u rt          |           S t          |           S n# t          $ r Y nw xY w|  d}t          |          )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5|,.. ,$$ +}\***7 l$9<T$TUU 	 lBI$788 	:+L99929$$+BI,<,BCCClBI$9:: 	7ry/555/===(666		7      
O
O
OC
S//s   D 
D*)D*c                     t          |           }t          |          }	 t          |          }t          |          }nK# t          t          f$ r7 t                              |          }t                              |          }Y nw xY w||k    S )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     s      &\\F&\\F#&\\&\\	" # # #]]6""]]6""# 8Os   ? ABB)directedc                j  
 t          t                    
t          t                    t          | |d          D ][\  }}|| dS |
f|ffD ]F\  }}|^}}}	|||f                             |	           |s|||f                             |	           G\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   | ]G}|         D ]<}|                              |          |                              |          k    V  =Hd S r|   )count).0edatar   r   s      r    	<genexpr>zedges_equal.<locals>.<genexpr>l  sZ      TT!bQReTTdr!u{{4  BqEKK$5$55TTTTTTTr!   )r   r#   r	   r   all)edges1edges2r   e1e2r   r3   urD   r   r   r   s             @@r    r   r     s    B 
T		B	T		Bff=== % %B:55"XBx( 	% 	%DAqKAq4adGNN4    %!Q$t$$$		% TTTTTrTTTTTTr!   c                 b    | j         |j         k    o| j        |j        k    o| 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  s7      	
fj  	)LFL(	)LFL(r!   c                 X    t          | dd          x}r|                                 dS dS )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     s9    
 /666u  r!   )r   
multigraphdefaultc                   |t           j        }| | n|}t          |t                    r|                    d          n|                                }t          |t                    r|                    d          n|                                }|0|r|st          j        d          |s|rt          j        d          |0|r|st          j        d          |s|rt          j        d          |S )a!  Assert that create_using has good properties

    This checks for desired directedness and multi-edge properties.
    It returns `create_using` unless that is `None` when it returns
    the optionally specified default value.

    Parameters
    ----------
    create_using : None, graph class or instance
        The input value of create_using for a function.
    directed : None or bool
        Whether to check `create_using.is_directed() == directed`.
        If None, do not assert directedness.
    multigraph : None or bool
        Whether to check `create_using.is_multigraph() == multigraph`.
        If None, do not assert multi-edge property.
    default : None or graph class
        The graph class to return if create_using is None.

    Returns
    -------
    create_using : graph class or instance
        The provided graph class or instance, or if None, the `default` value.

    Raises
    ------
    NetworkXError
        When `create_using` doesn't match the properties specified by `directed`
        or `multigraph` parameters.
    Nzcreate_using must be directedz!create_using must not be directedz"create_using must be a multi-graphz&create_using must not be a multi-graph)r&   Graphr   typeis_directedis_multigraphr'   )create_usingr   r   r   r   
G_directedG_multigraphs          r    check_create_usingr     s   > ($0gA(21d(;(;Pt$$$J,6q$,?,?V1??4(((Q__EVEVL 	DJ 	D"#BCCC 	HJ 	H"#FGGG 	Il 	I"#GHHH 	Ml 	M"#KL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      sC          # # # # # # 5 5 5 5 5 5 5 5 5 5 - - - - - - - - - -      .   ! ! !H1 1 1 1   .   B  B  B J &  &  &  &F  ,   <6X 6X 6X 6X 6Xv} 6X 6X 6XtL' L' L' L' L' L' L' L't? ? ? ?D  6 -2 NU NU NU NU NUb  ,   26$PT 1 1 1 1 1 1 1r!   