
    h{D                        S r SSKJr  SSKJr  SSKJr  SSKrSSK	J
r
  SSKJr  SS	/r\R                  " S
S9SS j5       rSS jrSS jr\" S5      \" S5      \R                  " S
S9S 5       5       5       rS rS rS rSS jrg)z%Functions for generating line graphs.    )defaultdict)partial)combinationsN)arbitrary_element)not_implemented_for
line_graphinverse_line_graphT)returns_graphc                 \    U R                  5       (       a  [        XS9nU$ [        U SUS9nU$ )ab  Returns the line graph of the graph or digraph `G`.

The line graph of a graph `G` has a node for each edge in `G` and an
edge joining those nodes if the two edges in `G` share a common node. For
directed graphs, nodes are adjacent exactly when the edges they represent
form a directed path of length two.

The nodes of the line graph are 2-tuples of nodes in the original graph (or
3-tuples for multigraphs, with the key of the edge as the third element).

For information about self-loops and more discussion, see the **Notes**
section below.

Parameters
----------
G : graph
    A NetworkX Graph, DiGraph, MultiGraph, or MultiDigraph.
create_using : NetworkX graph constructor, optional (default=nx.Graph)
   Graph type to create. If graph instance, then cleared before populated.

Returns
-------
L : graph
    The line graph of G.

Examples
--------
>>> G = nx.star_graph(3)
>>> L = nx.line_graph(G)
>>> print(sorted(map(sorted, L.edges())))  # makes a 3-clique, K3
[[(0, 1), (0, 2)], [(0, 1), (0, 3)], [(0, 2), (0, 3)]]

Edge attributes from `G` are not copied over as node attributes in `L`, but
attributes can be copied manually:

>>> G = nx.path_graph(4)
>>> G.add_edges_from((u, v, {"tot": u + v}) for u, v in G.edges)
>>> G.edges(data=True)
EdgeDataView([(0, 1, {'tot': 1}), (1, 2, {'tot': 3}), (2, 3, {'tot': 5})])
>>> H = nx.line_graph(G)
>>> H.add_nodes_from((node, G.edges[node]) for node in H)
>>> H.nodes(data=True)
NodeDataView({(0, 1): {'tot': 1}, (2, 3): {'tot': 5}, (1, 2): {'tot': 3}})

Notes
-----
Graph, node, and edge data are not propagated to the new graph. For
undirected graphs, the nodes in G must be sortable, otherwise the
constructed line graph may not be correct.

*Self-loops in undirected graphs*

For an undirected graph `G` without multiple edges, each edge can be
written as a set `\{u, v\}`.  Its line graph `L` has the edges of `G` as
its nodes. If `x` and `y` are two nodes in `L`, then `\{x, y\}` is an edge
in `L` if and only if the intersection of `x` and `y` is nonempty. Thus,
the set of all edges is determined by the set of all pairwise intersections
of edges in `G`.

Trivially, every edge in G would have a nonzero intersection with itself,
and so every node in `L` should have a self-loop. This is not so
interesting, and the original context of line graphs was with simple
graphs, which had no self-loops or multiple edges. The line graph was also
meant to be a simple graph and thus, self-loops in `L` are not part of the
standard definition of a line graph. In a pairwise intersection matrix,
this is analogous to excluding the diagonal entries from the line graph
definition.

Self-loops and multiple edges in `G` add nodes to `L` in a natural way, and
do not require any fundamental changes to the definition. It might be
argued that the self-loops we excluded before should now be included.
However, the self-loops are still "trivial" in some sense and thus, are
usually excluded.

*Self-loops in directed graphs*

For a directed graph `G` without multiple edges, each edge can be written
as a tuple `(u, v)`. Its line graph `L` has the edges of `G` as its
nodes. If `x` and `y` are two nodes in `L`, then `(x, y)` is an edge in `L`
if and only if the tail of `x` matches the head of `y`, for example, if `x
= (a, b)` and `y = (b, c)` for some vertices `a`, `b`, and `c` in `G`.

Due to the directed nature of the edges, it is no longer the case that
every edge in `G` should have a self-loop in `L`. Now, the only time
self-loops arise is if a node in `G` itself has a self-loop.  So such
self-loops are no longer "trivial" but instead, represent essential
features of the topology of `G`. For this reason, the historical
development of line digraphs is such that self-loops are included. When the
graph `G` has multiple edges, once again only superficial changes are
required to the definition.

References
----------
* Harary, Frank, and Norman, Robert Z., "Some properties of line digraphs",
  Rend. Circ. Mat. Palermo, II. Ser. 9 (1960), 161--168.
* Hemminger, R. L.; Beineke, L. W. (1978), "Line graphs and line digraphs",
  in Beineke, L. W.; Wilson, R. J., Selected Topics in Graph Theory,
  Academic Press Inc., pp. 271--305.

)create_usingF)	selfloopsr   )is_directed_lg_directed_lg_undirected)Gr   Ls      J/var/www/html/env/lib/python3.13/site-packages/networkx/generators/line.pyr   r      s6    L 	}}6 H 1LIH    c                 2   [         R                  " SXR                  S9nU R                  5       (       a  [	        U R
                  SS9OU R
                  nU" 5        H7  nUR                  U5        U" US   5       H  nUR                  XE5        M     M9     U$ )a
  Returns the line graph L of the (multi)digraph G.

Edges in G appear as nodes in L, represented as tuples of the form (u,v)
or (u,v,key) if G is a multidigraph. A node in L corresponding to the edge
(u,v) is connected to every node corresponding to an edge (v,w).

Parameters
----------
G : digraph
    A directed graph or directed multigraph.
create_using : NetworkX graph constructor, optional
   Graph type to create. If graph instance, then cleared before populated.
   Default is to use the same graph class as `G`.

r   defaultTkeys   )nxempty_graph	__class__is_multigraphr   edgesadd_nodeadd_edge)r   r   r   	get_edges	from_nodeto_nodes         r   r   r   {   sz      	q,<A 01/@/@d+aggI[		

9 1.GJJy* / ! Hr   c                   ^ [         R                  " SX R                  S9nU R                  5       (       a  [	        U R
                  SS9OU R
                  nU(       a  SOSn[        U 5       VVs0 s H  u  pgXv_M	     snnmU4S jn[        5       n	U  H  n
U" U
5       Vs/ s H)  n[        [        USS TR                  S	95      USS -   PM+     nn[        U5      S:X  a  UR                  US   5        [        U5       H>  u  pmU	R                  XU-   S  Vs/ s H  n[        [        X4US	95      PM     sn5        M@     M     UR                  U	5        U$ s  snnf s  snf s  snf )
a  Returns the line graph L of the (multi)graph G.

Edges in G appear as nodes in L, represented as sorted tuples of the form
(u,v), or (u,v,key) if G is a multigraph. A node in L corresponding to
the edge {u,v} is connected to every node corresponding to an edge that
involves u or v.

Parameters
----------
G : graph
    An undirected graph or multigraph.
selfloops : bool
    If `True`, then self-loops are included in the line graph. If `False`,
    they are excluded.
create_using : NetworkX graph constructor, optional (default=nx.Graph)
   Graph type to create. If graph instance, then cleared before populated.

Notes
-----
The standard algorithm for line graphs of undirected graphs does not
produce self-loops.

r   r   Tr   r   c                 $   > TU S      TU S      4$ )Nr   r    )edge
node_indexs    r   <lambda> _lg_undirected.<locals>.<lambda>   s    ja&9:d1g;N%Or   N   )key)r   r   r   r   r   r   	enumeratesettuplesortedgetlenr    updateadd_edges_from)r   r   r   r   r"   shiftinedge_key_functionr   uxnodesabr)   s                  @r   r   r      sR   0 	q,<A 01/@/@d+aggI AE $-Q<0<41!$<0J PEE LUUV<X<avae89AabEA<Xu:?JJuQx 
 e$DALL #u9;// &!->?@/ % * UH9 1 Ys   /E 0EE$directed
multigraphc                   ^
^ U R                  5       S:X  a  [        R                  " S5      $ U R                  5       S:X  a.  [        U 5      nUS4nUS4m[        R                  " UT4/5      nU$ U R                  5       S:  a,  U R                  5       S:X  a  Sn[        R                  " U5      e[        R                  " U 5      S:w  a  Sn[        R                  " U5      e[        U 5      n[        X5      nU R                   Vs0 s H  owS_M     snm
U H  nU H  nT
U==   S-  ss'   M     M     [        T
R                  5       5      S:  a  Sn[        R                  " U5      e[        U
4S jT
 5       5      n	[        R                  " 5       nUR                  U5        UR                  U	5        [        UR                  S5       H4  u  nm[!        U4S jU 5       5      (       d  M"  UR#                  UT5        M6     U$ s  snf )	a  Returns the inverse line graph of graph G.

If H is a graph, and G is the line graph of H, such that G = L(H).
Then H is the inverse line graph of G.

Not all graphs are line graphs and these do not have an inverse line graph.
In these cases this function raises a NetworkXError.

Parameters
----------
G : graph
    A NetworkX Graph

Returns
-------
H : graph
    The inverse line graph of G.

Raises
------
NetworkXNotImplemented
    If G is directed or a multigraph

NetworkXError
    If G is not a line graph

Notes
-----
This is an implementation of the Roussopoulos algorithm[1]_.

If G consists of multiple components, then the algorithm doesn't work.
You should invert every component separately:

>>> K5 = nx.complete_graph(5)
>>> P4 = nx.Graph([("a", "b"), ("b", "c"), ("c", "d")])
>>> G = nx.union(K5, P4)
>>> root_graphs = []
>>> for comp in nx.connected_components(G):
...     root_graphs.append(nx.inverse_line_graph(G.subgraph(comp)))
>>> len(root_graphs)
2

References
----------
.. [1] Roussopoulos, N.D. , "A max {m, n} algorithm for determining the graph H from
   its line graph G", Information Processing Letters 2, (1973), 108--112, ISSN 0020-0190,
   `DOI link <https://doi.org/10.1016/0020-0190(73)90029-X>`_

r   r   zninverse_line_graph() doesn't work on an edgeless graph. Please use this function on each component separately.zA line graph as generated by NetworkX has no selfloops, so G has no inverse line graph. Please remove the selfloops from G and try again.r,   zEG is not a line graph (vertex found in more than two partition cells)c              3   @   >#    U  H  nTU   S :X  d  M  U4v   M     g7f)r   Nr'   ).0r:   P_counts     r   	<genexpr>%inverse_line_graph.<locals>.<genexpr>/  s     7GqwqzQdqdGs   
c              3   ,   >#    U  H	  oT;   v   M     g 7fNr'   )rC   a_bitr>   s     r   rE   rF   4  s     )qezqs   )number_of_nodesr   r   r   Graphnumber_of_edgesNetworkXErrornumber_of_selfloops_select_starting_cell_find_partitionr<   maxvaluesr0   add_nodes_fromr   anyr!   )r   vr=   Hmsgstarting_cellPr:   pWrD   r>   s             @@r   r	   r	      s   j 	a~~a  	
				!a FFHHq!fX	
			q	 Q%6%6%8A%=E 	 s##	a A%T 	 s##)!,M)AWW%W!tW%GAAJ!OJ   7>>q Us##7G77A

AQQQWWa(1)q)))JJq! ) H &s   Hc                     Uu  p#X ;  a  [         R                  " SU S35      eX0U   ;  a  [         R                  " SU SU S35      e/ nX    H   nXPU   ;   d  M  UR                  X#U45        M"     U$ )z.Return list of all triangles containing edge eVertex  not in graphEdge (, ) not in graph)r   rM   append)r   er:   rU   triangle_listr;   s         r   
_trianglesre   9  s    DAz=9::!}s"QC~>??MT!9  !+  r   c                   ^ U H0  nX R                  5       ;  d  M  [        R                  " SU S35      e   [        [	        US5      5       H4  nUS   XS      ;  d  M  [        R                  " SUS    SUS    S35      e   [        [        5      mU H"  nX    H  nXQ;  d  M
  TU==   S-  ss'   M     M$     [        U4S	 jT 5       5      $ )
a  Test whether T is an odd triangle in G

Parameters
----------
G : NetworkX Graph
T : 3-tuple of vertices forming triangle in G

Returns
-------
True is T is an odd triangle
False otherwise

Raises
------
NetworkXError
    T is not a triangle in G

Notes
-----
An odd triangle is one in which there exists another vertex in G which is
adjacent to either exactly one or exactly all three of the vertices in the
triangle.

r]   r^   r,   r   r   r_   r`   ra   c              3   4   >#    U  H  nTU   S ;   v   M     g7f))r      Nr'   )rC   rU   T_nbrss     r   rE    _odd_triangle.<locals>.<genexpr>l  s     3FqvayF"Fs   )r<   r   rM   listr   r   intrT   )r   Tr:   rc   trU   ri   s         @r   _odd_trianglero   G  s    2 GGI""WQC}#=>>  ,q!$%Q4q1w""VAaD6AaD6#HII & FAzq	Q	   3F333r   c                 <   U R                  5       nU/nUR                  [        [        US5      5      5        [        U5      nUR	                  5       S:  a  UR                  5       n[        X%   5      nUS:w  a  U/[        X%   5      -   nU H3  nU H*  nXX:w  d  M
  XU   ;  d  M  Sn	[        R                  " U	5      e   M5     UR                  [        U5      5        UR                  [        [        US5      5      5        XG-  nUR	                  5       S:  a  M  U$ )a9  Find a partition of the vertices of G into cells of complete graphs

Parameters
----------
G : NetworkX Graph
starting_cell : tuple of vertices in G which form a cell

Returns
-------
List of tuples of vertices of G

Raises
------
NetworkXError
    If a cell is not a complete subgraph then G is not a line graph
r,   r   z>G is not a line graph (partition cell not a complete subgraph))copyremove_edges_fromrk   r   rL   popr3   r   rM   rb   r0   )
r   rX   G_partitionrY   partitioned_verticesr:   deg_unew_cellrU   rW   s
             r   rP   rP   o  s   " &&(K	A!!$|M1'E"FG.

%
%
'!
+ $$&KN#A: sT+.11H!AQ!n%<G  !..s33 "  HHU8_%))$|Ha/H*IJ , ' 
%
%
'!
+( Hr   c                    Uc  [        U R                  5       5      nOiUnUS   U R                  5       ;  a  [        R                  " SUS    S35      eUS   XS      ;  a%  SUS    SUS    S3n[        R                  " U5      e[        X5      n[        U5      nUS:X  a  UnU$ US:X  a\  US   nUu  pn
[        [        XU
45      5      n[        [        X	U
45      5      nUS:X  a  US:X  a  UnU$ [        X	U
4S9$ [        XU
4S9$ Sn/ nU H+  n[        X5      (       d  M  US-  nUR                  U5        M-     US	:X  a
  US:X  a  WnU$ US-
  Us=::  a  U::  ax  O  Ou[        5       nU H  nU H  nUR                  U5        M     M     U H5  nU H,  nUU:w  d  M  UU U   ;  d  M  S
n[        R                  " U5      e   M7     [        U5      nU$ Sn[        R                  " U5      e)a  Select a cell to initiate _find_partition

Parameters
----------
G : NetworkX Graph
starting_edge: an edge to build the starting cell from

Returns
-------
Tuple of vertices in G

Raises
------
NetworkXError
    If it is determined that G is not a line graph

Notes
-----
If starting edge not specified then pick an arbitrary edge - doesn't
matter which. However, this function may call itself requiring a
specific starting edge. Note that the r, s notation for counting
triangles is the same as in the Roussopoulos paper cited above.
r   r]   r^   r   zstarting_edge (r`   z) is not in the Graph)starting_edger,   zCG is not a line graph (odd triangles do not form complete subgraph)zNG is not a line graph (incorrect number of odd triangles around starting edge))r   r   r<   r   rM   re   r3   rO   ro   rb   r/   addr0   )r   ry   rc   rW   e_trianglesrrX   rm   r=   r>   cac_edgesbc_edgessodd_trianglestriangle_nodesr;   r:   rU   s                      r   rO   rO     s<   0 aggi(Q4qwwy ""WQqTF-#@AAQ4q1w#AaD6AaD61FGC""3''Q"KKAAvf e 
a Naz!V,-z!V,-q=1} !P M -Q!fEE(a&AA AQ""Q$$Q'  6a1fM2 1 Ua_1_ UN"A"&&q)  # $'AAv1AaD==  !..s33 ( $ ".1M 	6  ""3''r   rH   )FN)__doc__collectionsr   	functoolsr   	itertoolsr   networkxr   networkx.utilsr   networkx.utils.decoratorsr   __all___dispatchabler   r   r   r	   re   ro   rP   rO   r'   r   r   <module>r      s    + #  "  , 9-
. %i &iX<=@ Z \"%Z & # !Zz%4P*ZXr   