U
    ¹mœd?D  ã                   @   s¬   d Z ddlmZ ddlmZ ddlmZ ddlZddl	m
Z
 ddlmZ dd	gZdd
d„Zddd„Zddd„Zedƒedƒdd	„ ƒƒZdd„ Zdd„ Zdd„ Zddd„ZdS )z%Functions for generating line graphs.é    )Údefaultdict)Úpartial)ÚcombinationsN)Úarbitrary_element)Únot_implemented_forÚ
line_graphÚinverse_line_graphc                 C   s(   |   ¡ rt| |d�}nt| d|d�}|S )a¤  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	   )Zis_directedÚ_lg_directedÚ_lg_undirected)ÚGr	   ÚL© r   úQ/home/sam/Atlas/atlas_env/lib/python3.8/site-packages/networkx/generators/line.pyr      s    ec                 C   sf   t jd|| jd�}|  ¡ r(t| jdd�n| j}|ƒ D ],}| |¡ ||d ƒD ]}| ||¡ qNq4|S )a6  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_edgesZ	from_nodeZto_noder   r   r   r   y   s    

r   Fc           
         sÞ   t jd|| jd�}|  ¡ r(t| jdd�n| j}|r6dnd}dd„ t| ƒD ƒ‰‡fdd	„‰tƒ }| D ]l}‡fd
d„||ƒD ƒ}t|ƒdkr–| 	|d ¡ t|ƒD ].\}	‰ | 
‡ ‡fdd„||	| d… D ƒ¡ qžqb| |¡ |S )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                 S   s   i | ]\}}||“qS r   r   )Ú.0ÚiÚnr   r   r   Ú
<dictcomp>¸   s      z"_lg_undirected.<locals>.<dictcomp>c                    s   ˆ | d  ˆ | d  fS )Nr   r   r   )Úedge©Ú
node_indexr   r   Ú<lambda>»   ó    z _lg_undirected.<locals>.<lambda>c                    s2   g | ]*}t t|d d… ˆ jd�ƒ|dd …  ‘qS )Né   ©Úkey)ÚtupleÚsortedÚget)r   Úxr#   r   r   Ú
<listcomp>Â   s     z"_lg_undirected.<locals>.<listcomp>c                    s    g | ]}t tˆ |fˆd �ƒ‘qS )r(   )r*   r+   )r   Úb)ÚaÚedge_key_functionr   r   r.   Í   s   ÿN)r   r   r   r   r   r   Ú	enumerateÚsetÚlenr   ÚupdateZadd_edges_from)
r   r
   r	   r   r   Úshiftr   ÚuÚnodesr   r   )r0   r1   r$   r   r   —   s$    þÿ
r   ZdirectedZ
multigraphc           
         sf  |   ¡ dkrt d¡S |   ¡ dkrNt| ƒ}|df}|df‰t |ˆfg¡}|S |   ¡ dkrt|  ¡ dkrtd}t |¡‚t | ¡dkr�d}t |¡‚t| ƒ}t	| |ƒ}dd„ | j
D ƒ‰ |D ]}|D ]}ˆ |  d7  < q¾q¶tˆ  ¡ ƒdkrôd}t |¡‚t‡ fd	d
„ˆ D ƒƒ}	t ¡ }| |¡ | |	¡ t|j
dƒD ].\}‰t‡fdd
„|D ƒƒ�r2| |ˆ¡ �q2|S )af  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.z‰A 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.c                 S   s   i | ]
}|d “qS )r   r   ©r   r7   r   r   r   r!   $  s      z&inverse_line_graph.<locals>.<dictcomp>r'   zEG is not a line graph (vertex found in more than two partition cells)c                 3   s    | ]}ˆ | d kr|fV  qdS )r   Nr   r9   )ÚP_countr   r   Ú	<genexpr>,  s      z%inverse_line_graph.<locals>.<genexpr>c                 3   s   | ]}|ˆ kV  qd S )Nr   )r   Za_bit)r/   r   r   r;   1  s     )Znumber_of_nodesr   r   r   ZGraphÚnumber_of_edgesÚNetworkXErrorZnumber_of_selfloopsÚ_select_starting_cellÚ_find_partitionr8   ÚmaxÚvaluesr*   Zadd_nodes_fromr   Úanyr   )
r   Úvr0   ÚHÚmsgÚstarting_cellÚPÚpr7   ÚWr   )r:   r/   r   r   ×   sB    4
ÿ
ÿ




c                 C   sx   |\}}|| kr"t  d|› d�¡‚|| | krFt  d|› d|› d�¡‚g }| | D ] }|| | krR| |||f¡ qR|S )z.Return list of all triangles containing edge eúVertex ú not in graphúEdge (ú, ú) not in graph)r   r=   Úappend)r   Úer7   rC   Ztriangle_listr-   r   r   r   Ú
_triangles6  s    rQ   c                    s¾   |D ]"}||   ¡ krt d|› d�¡‚qtt|dƒƒD ]8}|d | |d  kr6t d|d › d|d › d�¡‚q6ttƒ‰ |D ]*}| | D ]}||krˆˆ |  d7  < qˆq|t‡ fd	d
„ˆ D ƒƒS )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.

    rJ   rK   r'   r   r   rL   rM   rN   c                 3   s   | ]}ˆ | d kV  qdS ))r   é   Nr   )r   rC   ©ZT_neighborsr   r   r;   i  s     z _odd_triangle.<locals>.<genexpr>)r8   r   r=   Úlistr   r   ÚintrB   )r   ÚTr7   rP   ÚtrC   r   rS   r   Ú_odd_triangleD  s    "rX   c           
      C   sÊ   |   ¡ }|g}| tt|dƒƒ¡ t|ƒ}| ¡ dkrÆ| ¡ }t|| ƒ}|dkr*|gt|| ƒ }|D ]0}|D ]&}||krp||| krpd}	t |	¡‚qpqh| 	t
|ƒ¡ | tt|dƒƒ¡ ||7 }q*|S )ai  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))ÚcopyZremove_edges_fromrT   r   r<   Úpopr4   r   r=   rO   r*   )
r   rF   ZG_partitionrG   Zpartitioned_verticesr7   Zdeg_uZnew_cellrC   rE   r   r   r   r?   l  s&    ÿ
r?   c                 C   s  |dkrt |  ¡ ƒ}nb|}|d |  ¡ kr@t d|d › d�¡‚|d | |d  krxd|d › d|d › d�}t |¡‚t| |ƒ}t|ƒ}|dkrš|}�nf|dk�r|d }|\}}	}
tt| ||
fƒƒ}tt| |	|
fƒƒ}|dk�r|dkrò|}nt| |	|
fd	�S nt| ||
fd	�S nêd}g }|D ]$}t| |ƒ�r"|d7 }| 	|¡ �q"|d
k�rb|dk�rb|}nž|d |  k�r~|k�ròn npt
ƒ }|D ]}|D ]}| |¡ �q”�qŒ|D ]8}|D ],}||k�r¶|| | k�r¶d}t |¡‚�q¶�q®t|ƒ}nd}t |¡‚|S )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.
    Nr   rJ   rK   r   zstarting_edge (rM   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   r8   r   r=   rQ   r4   r>   rX   rO   r3   Úaddr*   )r   r[   rP   rE   Ze_trianglesÚrrF   rV   r0   r/   ÚcZac_edgesZbc_edgesÚsZodd_trianglesZtriangle_nodesr-   r7   rC   r   r   r   r>   ™  s\    




 ÿ
ÿ
r>   )N)N)FN)N)Ú__doc__Úcollectionsr   Ú	functoolsr   Ú	itertoolsr   Znetworkxr   Znetworkx.utilsr   Znetworkx.utils.decoratorsr   Ú__all__r   r   r   r   rQ   rX   r?   r>   r   r   r   r   Ú<module>   s"   
l

@](-