K i SdZddlZddlZddlmZddlmZmZmZddl m Z m Z ddl Z gdZddZdZdd Zdd Zdd Zd Zdd ZdZddZGddej0ZGddZddZdZdZdZdZdddddZ 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)IterableIteratorSized)chaintee)flattenmake_list_of_intsdict_to_numpy_arrayarbitrary_elementpairwisegroupscreate_random_statecreate_py_random_statePythonRandomInterfacePythonRandomViaNumpyBits nodes_equal edges_equal graphs_equal _clear_cachec t|ttzrt|tr|S|g}|D]G}t|ttzrt|tr|j |Return flattened version of (possibly nested) iterable object.) isinstancerrstrappendr tuple)objresultitems Y/mnt/ssd/data/python-lab/Trading/venv/lib/python3.12/site-packages/networkx/utils/misc.pyr r -sr c8e+ , 30D  ~"$5 01Zc5J MM$  D& ! " =ct|tsGg}|D]>}d|} t|}||k7rt j ||j |@|St|D]F\}}d|}t|tr t|}||k7rt j ||||<H|S#t$rt j |dwxYw#t$rt j |dwxYw)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 zsequence is not all integers: N)rlistint ValueErrornx NetworkXErrorr enumerate)sequencerierrmsgiiindxs r r r ;s h % A5aS9F 9VQw&&v.. MM"   X& a1!5 a   5QB 7""6* *  O% 9&&v.D8 9 5""6* 4 5s B. C. C C1c^ t||S#ttf$rt||cYSwxYw)zPConvert a dictionary of dictionaries to a numpy array with optional mapping.)_dict_to_numpy_array2AttributeError TypeError_dict_to_numpy_array1)dmappings r r r _s71$Q00 I &1%Q001s ,,c ddl}|wt|j}|jD]$\}}|j |j&t t |tt|}t|}|j||f}|jD]+\}} |jD]\} } ||| || | f<-|S#t$rY%wxYw)zYConvert a dictionary of dictionaries to a 2d numpy array with optional mapping. rN) numpysetkeysitemsupdatedictziprangelenzerosKeyError) r3r4npskvnak1r*k2js r r/r/js  MGGI DAq HHQVVX  s1eCFm,- G A !QAA]]_ EB B%)!Q$  H  s C C('C(c ddl}|@t|j}tt |t t |}t |}|j|}|jD]\}}||}||||<|S)zJConvert a dictionary of numbers to a 1d numpy array with optional mapping.rN) r6r7r8r;r<r=r>r?r9)r3r4rArBrErFrGr*s r r2r2s~ Ms1eCFm,- G A  AA BKu! Hr!c`t|tr tdtt |S)aReturns 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)rrr%nextiter)iterables r r r s*~(H%KLL X r!ct|\}}t|d}|durt|t||fSt||S)z&s -> (s0, s1), (s1, s2), (s2, s3), ...NT)r rLr<r)rNcyclicrFbfirsts r rrsC x=DAq DME ~1eAx()) q!9r!ctt}|jD]\}}||j|t |S)aConverts 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'}} )rr7r9addr;) many_to_one one_to_manyrDrCs r rrsG c"K!!#1A1  r!chddl}|||jur |jjjSt ||jj r|St |t r|jj |St ||jjr|S|d}t|)aReturns 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. rNzW cannot be used to create a numpy.random.RandomState or numpy.random.Generator instance) r6randommtrand_randr RandomStater$ Generatorr% random_staterAmsgs r rrs|ryy8yy%%%, 5 56,$yy$$\22, 3 34 .* * S/r!c6eZdZdZd dZdZdZdZdZdZ y) raProvide 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 ddl}|-j j j|_d|_ y||_d|_ y#t$rd}tj|tYewxYwNrz.numpy not found, only random.random available.) r6 ImportErrorwarningswarn ImportWarningrXrYrZ_rng gauss_nextselfrngrAr_s r __init__z!PythonRandomViaNumpyBits.__init__%sg .  ; ((..DI  DI .BC MM#} - .sA%A,+A,c6|jjS)z7Get the next random number in the range 0.0 <= X < 1.0.rgrXrjs r rXzPythonRandomViaNumpyBits.random5syy!!r!c|dkr td|dzdz}tj|jj |d}||dz|z z S)z:getrandbits(k) -> x. Generates an int with k random bits.rz#number of bits must be non-negativebig)r%r$ from_bytesrgbytes)rjrCnumbytesxs r getrandbitsz$PythonRandomViaNumpyBits.getrandbits9sS q5BC CEa< NN499??84e <X\A%&&r!c6|jjSN)rg __getstate__ros r getstatez!PythonRandomViaNumpyBits.getstateAsyy%%''r!c:|jj|yrz)rg __setstate__)rjstates r setstatez!PythonRandomViaNumpyBits.setstateDs u%r!ctd)zDo nothing override method.z2seed() not implemented in PythonRandomViaNumpyBits)NotImplementedError)rjargskwdss r seedzPythonRandomViaNumpyBits.seedGs!"VWWr!rz) __name__ __module__ __qualname____doc__rlrXrxr|rrr!r rrs&" "'(&Xr!rcVeZdZdZddZdZdZddZdZdZ d Z d Z d Z d Z d Zy)rz{PythonRandomInterface is included for backward compatibility New code should use PythonRandomViaNumpyBits instead. Nc ddl}|&j j j|_y||_y#t$rd}tj|tYWwxYwrb) r6rcrdrerfrXrYrZrgris r rlzPythonRandomInterface.__init__RsS .  ; ((..DIDI .BC MM#} - .s6%AAc6|jjSrzrnros r rXzPythonRandomInterface.random^syy!!r!cH|||z |jjzzSrzrn)rjrFrQs r uniformzPythonRandomInterface.uniformas#AETYY--////r!c2ddl}|d|}}|dkDr't|j}|j||St |j|j j r|jj||S|jj||S)Nr) r6rrg randrangerrXr\integersrandintrjrFrQrAtmp_rngs r rzPythonRandomInterface.randrangeds 9aqA " ".tyy9G$$Q* * dii!4!4 599%%a+ +yy  A&&r!cddl}t|j|jjr*|jj dt |}||S|jjdt |}||S)Nr)r6rrgrXr\rr>r)rjseqrAidxs r choicezPythonRandomInterface.choicessg dii!4!4 5))$$QC1C3x))##As3x0C3xr!c:|jj||Srz)rgnormal)rjmusigmas r gausszPythonRandomInterface.gauss|syyE**r!c8|jj|Srz)rgshuffle)rjrs r rzPythonRandomInterface.shufflesyy  %%r!cR|jjt||fdS)NF)sizereplace)rgrr#)rjrrCs r samplezPythonRandomInterface.samples$yyS eDDr!c2ddl}|dkDr't|j}|j||St |j|j j r|jj||dzS|jj||dzS)Nrr)r6rrgrrrXr\rrs r rzPythonRandomInterface.randints{ " ".tyy9G??1a( ( dii!4!4 599%%aQ/ /yy  AE**r!c>|jjd|z S)Nr)rg exponential)rjscales r expovariatez!PythonRandomInterface.expovariatesyy$$QY//r!c8|jj|Srz)rgpareto)rjshapes r paretovariatez#PythonRandomInterface.paretovariatesyy&&r!rz)rrrrrlrXrrrrrrrrrrr!r rrMs? "0 '+& E +0'r!rc||turtjSt|tjr|St|trtj|S ddl}t|t tzr|St||jjr t|S||jur)t|jjjSt||jjr8||jjjur t|St |S|d}t|#t$rYwxYw)a5Returns 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 `_. - More discussion about this support also appears in `gh-6869#comment `_. - 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. Nrz4 cannot be used to generate a random.Random instance)rX_instrRandomr$r6rrr\rYrZr[rcr%r]s r rrsJ|v5||, .,$}}\**7 l$9>$':+;+;D+AA  !  ! ! r!c|j|jk(xr4|j|jk(xr|j|jk(S)aCheck 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. )adjnodesgraph)graph1graph2s r rr;sC  fjj  ) LLFLL ( ) LLFLL (r!cDt|ddx}r|jyy)zClear the cache of a graph (currently stores converted graphs). Caching is controlled via ``nx.config.cache_converted_graphs`` configuration. __networkx_cache__N)getattrclear)Gcaches r rrQs' /66u6 7r!)directed multigraphdefaultc|tj}||n|}t|tr|j dn|j }t|tr|j dn|j }|2|r|stj d|s|rtj d|2|r|stj d|s|rtj 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. Nzcreate_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&Graphrtype is_directed is_multigraphr') create_usingrrrr G_directed G_multigraphs r check_create_usingrZs>(($0 gA(21d(;t$J,6q$,?1??4(Q__EVL J""#BC CJ""#FG G l""#GH Hl""#KL L Hr!rz)F)!rrXrdrrcollections.abcrrr itertoolsrr networkxr&__all__r r r r/r2r rrrrrrrrrrrrrr!r rs #55  . !H1 .  B L,<6Xv}}6XtL'L't?D64n,26$PT1 r!