K i}7HdZddlmZddlZddlmZmZgdZejdZ ejdZ d Z d Z d Zejdd Zejdd ZejddZedejddZy)z Eulerian circuits and graphs. ) combinationsN)arbitrary_elementnot_implemented_for) is_eulerianeulerian_circuiteulerizeis_semieulerianhas_eulerian_path eulerian_pathcjr+tfdDxrtjStdj Dxrtj S)apReturns True if and only if `G` is Eulerian. A graph is *Eulerian* if it has an Eulerian circuit. An *Eulerian circuit* is a closed walk that includes each edge of a graph exactly once. Graphs with isolated vertices (i.e. vertices with zero degree) are not considered to have Eulerian circuits. Therefore, if the graph is not connected (or not strongly connected, for directed graphs), this function returns False. Parameters ---------- G : NetworkX graph A graph, either directed or undirected. Examples -------- >>> nx.is_eulerian(nx.DiGraph({0: [3], 1: [2], 2: [3], 3: [0, 1]})) True >>> nx.is_eulerian(nx.complete_graph(5)) True >>> nx.is_eulerian(nx.petersen_graph()) False If you prefer to allow graphs with isolated vertices to have Eulerian circuits, you can first remove such vertices and then call `is_eulerian` as below example shows. >>> G = nx.Graph([(0, 1), (1, 2), (0, 2)]) >>> G.add_node(3) >>> nx.is_eulerian(G) False >>> G.remove_nodes_from(list(nx.isolates(G))) >>> nx.is_eulerian(G) True c3dK|]'}j|j|k()ywN in_degree out_degree).0nGs _/mnt/ssd/data/python-lab/Trading/venv/lib/python3.12/site-packages/networkx/algorithms/euler.py zis_eulerian..As+ 23AKKNall1o - s-0c32K|]\}}|dzdk(yw)rrNrvds rrzis_eulerian..Fs1daq1uz1) is_directedallnxis_strongly_connecteddegree is_connectedrs`rrrseR }} 78  *&&q) * 1ahhj1 1 Hbooa6HHc4t|xr t| S)zReturn True iff `G` is semi-Eulerian. G is semi-Eulerian if it has an Eulerian path but no Eulerian circuit. See Also -------- has_eulerian_path is_eulerian )r rr$s rr r Is Q  6 A$66r%c6tsytr tSjr5fdD\}}j |j |kDr|S|SDcgc]}j |dzdk7s|c}d}|Scc}w)zaReturn a suitable starting vertex for an Eulerian path. If no path exists, return None. Nc3jK|]*}j|j|k7s'|,ywrr)rrrs rrz#_find_path_start..cs(D!++a.ALLO"C!Ds(33rr)r rrrrrr")rv1v2rstarts` r_find_path_startr,Ws Q 1~ ##}}DQDB << akk"o -II6q!qA!56q9 7s -B Bc#hK|jr|j}|j}n|j}|j}|g}d}|rf|d}||dk(r|||f|}|j n7t ||\}}|j||j|||reyyw)Nr rr out_edgesr"edgespoprappend remove_edge) rsourcer"r1 vertex_stack last_vertexcurrent_vertex_ next_vertexs r_simplegraph_eulerian_circuitr;ps}} 8LK %b) . !Q &&"N33(K    .u^/DENA{    , MM.+ 6 s B-B20B2c#K|jr|j}|j}n|j}|j}|dfg}d}d}|rt|d\}}||dk(r||||f||}}|j n?t ||d} | \} } } |j| | f|j|| | |rsyyw)Nr.rT)keysr/) rr5r"r1r6r7last_keyr8 current_keytripler9r:next_keys r_multigraph_eulerian_circuitrBs}} TN#LKH &22&6# . !Q &&"NH==$2KK    &u^$'GHF'- $A{H   h 7 8 MM.+x @ s B?CCc#`Kt|stjd|jr|j }n|j }| t |}|jr&t||D]\}}}|r|||f||fyt||Ed{y7w)a.Returns an iterator over the edges of an Eulerian circuit in `G`. An *Eulerian circuit* is a closed walk that includes each edge of a graph exactly once. Parameters ---------- G : NetworkX graph A graph, either directed or undirected. source : node, optional Starting node for circuit. keys : bool If False, edges generated by this function will be of the form ``(u, v)``. Otherwise, edges will be of the form ``(u, v, k)``. This option is ignored unless `G` is a multigraph. Returns ------- edges : iterator An iterator over edges in the Eulerian circuit. Raises ------ NetworkXError If the graph is not Eulerian. See Also -------- is_eulerian Notes ----- This is a linear time implementation of an algorithm adapted from [1]_. For general information about Euler tours, see [2]_. References ---------- .. [1] J. Edmonds, E. L. Johnson. Matching, Euler tours and the Chinese postman. Mathematical programming, Volume 5, Issue 1 (1973), 111-114. .. [2] https://en.wikipedia.org/wiki/Eulerian_path Examples -------- To get an Eulerian circuit in an undirected graph:: >>> G = nx.complete_graph(3) >>> list(nx.eulerian_circuit(G)) [(0, 2), (2, 1), (1, 0)] >>> list(nx.eulerian_circuit(G, source=1)) [(1, 2), (2, 0), (0, 1)] To get the sequence of vertices in an Eulerian circuit:: >>> [u for u, v in nx.eulerian_circuit(G)] [0, 2, 1] zG is not Eulerian.N) rr NetworkXErrorrreversecopyr is_multigraphrBr;rr5r=urks rrrs~ q>344}} IIK FFH ~"1%3Av> GAq!Ag d   1F;;;sB$B.&B,'B.c tj|ry|jr|j}|j}|||||z dk7ryd}d}|D]7}||||z dk(r|dz }||||z dk(r|dz }+||||k7s7y|dkxr|dkxrtj |S||j |dzdk7rytd|j Ddk(xrtj|S)aReturn True iff `G` has an Eulerian path. An Eulerian path is a path in a graph which uses each edge of a graph exactly once. If `source` is specified, then this function checks whether an Eulerian path that starts at node `source` exists. A directed graph has an Eulerian path iff: - at most one vertex has out_degree - in_degree = 1, - at most one vertex has in_degree - out_degree = 1, - every other vertex has equal in_degree and out_degree, - and all of its vertices belong to a single connected component of the underlying undirected graph. If `source` is not None, an Eulerian path starting at `source` exists if no other node has out_degree - in_degree = 1. This is equivalent to either there exists an Eulerian circuit or `source` has out_degree - in_degree = 1 and the conditions above hold. An undirected graph has an Eulerian path iff: - exactly zero or two vertices have odd degree, - and all of its vertices belong to a single connected component. If `source` is not None, an Eulerian path starting at `source` exists if either there exists an Eulerian circuit or `source` has an odd degree and the conditions above hold. Graphs with isolated vertices (i.e. vertices with zero degree) are not considered to have an Eulerian path. Therefore, if the graph is not connected (or not strongly connected, for directed graphs), this function returns False. Parameters ---------- G : NetworkX Graph The graph to find an euler path in. source : node, optional Starting node for path. Returns ------- Bool : True if G has an Eulerian path. Examples -------- If you prefer to allow graphs with isolated vertices to have Eulerian path, you can first remove such vertices and then call `has_eulerian_path` as below example shows. >>> G = nx.Graph([(0, 1), (1, 2), (0, 2)]) >>> G.add_node(3) >>> nx.has_eulerian_path(G) False >>> G.remove_nodes_from(list(nx.isolates(G))) >>> nx.has_eulerian_path(G) True See Also -------- is_eulerian eulerian_path TFrrc32K|]\}}|dzdk(yw)rrLNrrs rrz$has_eulerian_path..Ks5$!Q1q5A:5r) r rrrris_weakly_connectedr"sumr#)rr5insoutsunbalanced_insunbalanced_outsrs rr r s,~ ~~a}}kk||  $v,V"<"A A1vQ1$!#a3q6!Q&1$Q47"   a  VOq$8 VR=S=STU=V  !((6"2Q"6!";5!((*55:Qrq?QQr%c #@Kt||stjd|jr|j }|tj |dur t |}|jr&t||D]\}}}|r|||f||fyt||Ed{y|j}| t |}|jro|r7tt||Dcgc] \}}}|||f c}}}Ed{ytt||Dcgc] \}}}||f c}}}Ed{ytt||Dcgc] \}}||f c}}Ed{y7cc}}}w7wcc}}}w7Jcc}}w7w)aReturn an iterator over the edges of an Eulerian path in `G`. Parameters ---------- G : NetworkX Graph The graph in which to look for an eulerian path. source : node or None (default: None) The node at which to start the search. None means search over all starting nodes. keys : Bool (default: False) Indicates whether to yield edge 3-tuples (u, v, edge_key). The default yields edge 2-tuples Yields ------ Edge tuples along the eulerian path. Warning: If `source` provided is not the start node of an Euler path will raise error even if an Euler Path exists. zGraph has no Eulerian paths.NF) r r rDrrErr,rGrBr;rFreversedrHs rr r Ns, Q '=>>}} IIK >R^^A.%7%a(F ?? 76B 1aQ'MQ$J   5Q? ? ? FFH >%a(F ?? #.J1f.UVV71aaAYV$+G6+RSS1aaVS $A!V$LMDAq!QM   @W T N smB+F-F.A F7F  FF F.F = F F F#F 1 F<F=FF FFdirectedT) returns_graphc |jdk(rtjdtj|stjd|j Dcgc]\}}|dzdk(s|}}}tj |}t|dk(r|St|dDcgc]!\}}||tj|||if#}}}t|dz}tj}|D]D\}}|jD],\}} ||k7s |j|||t| z | .Ftjttj|} | jD]>\}}|||d} |j!tj"j%| @|Scc}}wcc}}w) aTransforms a graph into an Eulerian graph. If `G` is Eulerian the result is `G` as a MultiGraph, otherwise the result is a smallest (in terms of the number of edges) multigraph whose underlying simple graph is `G`. Parameters ---------- G : NetworkX graph An undirected graph Returns ------- G : NetworkX multigraph Raises ------ NetworkXError If the graph is not connected. See Also -------- is_eulerian eulerian_circuit References ---------- .. [1] J. Edmonds, E. L. Johnson. Matching, Euler tours and the Chinese postman. Mathematical programming, Volume 5, Issue 1 (1973), 111-114. .. [2] https://en.wikipedia.org/wiki/Eulerian_path .. [3] http://web.math.princeton.edu/math_alive/5/Notes1.pdf Examples -------- >>> G = nx.complete_graph(10) >>> H = nx.eulerize(G) >>> nx.is_eulerian(H) True rzCannot Eulerize null graphzG is not connectedrrL)r5target)weightpathr[)orderr NetworkXPointlessConceptr#rDr" MultiGraphlenr shortest_pathGraphitemsadd_edgelistmax_weight_matchingr1add_edges_fromutilspairwise) rrrodd_degree_nodesmodd_deg_pairs_pathsupper_bound_on_max_path_lengthGpPsP best_matchingr[s rr r sV wwyA~))*FGG ??1 344&'hhj?daAEQJ?? aA ! !!115 Aq Q  1Q7 89&)VaZ" B$2HHJ DAqAv q!?#a&!Hq HHT""8"8"<=>M##%21!uQx **4012 HE@ s&G 7G 2&G)NFr)__doc__ itertoolsrnetworkxr rgrr__all__ _dispatchablerr r,r;rBrr r r rr%rrvs#: 0I0If 7 727,A0M<M<`[R[R|33lZ %O &!O r%