U
    9vf|3                     @   s   d Z ddlZddlZddlmZ ddlmZmZ ddddd	d
gZ	G dd	 d	ej
Zededdd ZejfddZdd Zdd Zdd Zdd Zdd ZdejfddZeddd
 ZdS )z
Algorithms for chordal graphs.

A graph is chordal if every cycle of length at least 4 has a chord
(an edge joining two nodes not adjacent in the cycle).
https://en.wikipedia.org/wiki/Chordal_graph
    N)connected_components)arbitrary_elementnot_implemented_for
is_chordalfind_induced_nodeschordal_graph_cliqueschordal_graph_treewidthNetworkXTreewidthBoundExceededcomplete_to_chordal_graphc                   @   s   e Zd ZdZdS )r	   zVException raised when a treewidth bound has been provided and it has
    been exceededN)__name__
__module____qualname____doc__ r   r   ?/tmp/pip-unpacked-wheel-_lngutwb/networkx/algorithms/chordal.pyr	      s   ZdirectedZ
multigraphc                 C   s   t t| dkS )u  Checks whether G is a chordal graph.

    A graph is chordal if every cycle of length at least 4 has a chord
    (an edge joining two nodes not adjacent in the cycle).

    Parameters
    ----------
    G : graph
      A NetworkX graph.

    Returns
    -------
    chordal : bool
      True if G is a chordal graph and False otherwise.

    Raises
    ------
    NetworkXNotImplemented
        The algorithm does not support DiGraph, MultiGraph and MultiDiGraph.

    Examples
    --------
    >>> e = [
    ...     (1, 2),
    ...     (1, 3),
    ...     (2, 3),
    ...     (2, 4),
    ...     (3, 4),
    ...     (3, 5),
    ...     (3, 6),
    ...     (4, 5),
    ...     (4, 6),
    ...     (5, 6),
    ... ]
    >>> G = nx.Graph(e)
    >>> nx.is_chordal(G)
    True

    Notes
    -----
    The routine tries to go through every node following maximum cardinality
    search. It returns False when it finds that the separator for any node
    is not a clique.  Based on the algorithms in [1]_.

    References
    ----------
    .. [1] R. E. Tarjan and M. Yannakakis, Simple linear-time algorithms
       to test chordality of graphs, test acyclicity of hypergraphs, and
       selectively reduce acyclic hypergraphs, SIAM J. Comput., 13 (1984),
       pp. 566–579.
    r   )len_find_chordality_breakerGr   r   r   r      s    6c                 C   s   t | stdt| }||| t }t|||}|r~|\}}}	|| |D ]}
|
|krV|||
 qVt|||}q:|r|| | | D ]*}t	|t| | @ dkr||  qq|S )a  Returns the set of induced nodes in the path from s to t.

    Parameters
    ----------
    G : graph
      A chordal NetworkX graph
    s : node
        Source node to look for induced nodes
    t : node
        Destination node to look for induced nodes
    treewidth_bound: float
        Maximum treewidth acceptable for the graph H. The search
        for induced nodes will end as soon as the treewidth_bound is exceeded.

    Returns
    -------
    induced_nodes : Set of nodes
        The set of induced nodes in the path from s to t in G

    Raises
    ------
    NetworkXError
        The algorithm does not support DiGraph, MultiGraph and MultiDiGraph.
        If the input graph is an instance of one of these classes, a
        :exc:`NetworkXError` is raised.
        The algorithm can only be applied to chordal graphs. If the input
        graph is found to be non-chordal, a :exc:`NetworkXError` is raised.

    Examples
    --------
    >>> G = nx.Graph()
    >>> G = nx.generators.classic.path_graph(10)
    >>> induced_nodes = nx.find_induced_nodes(G, 1, 9, 2)
    >>> sorted(induced_nodes)
    [1, 2, 3, 4, 5, 6, 7, 8, 9]

    Notes
    -----
    G must be a chordal graph and (s,t) an edge that is not in G.

    If a treewidth_bound is provided, the search for induced nodes will end
    as soon as the treewidth_bound is exceeded.

    The algorithm is inspired by Algorithm 4 in [1]_.
    A formal definition of induced node can also be found on that reference.

    References
    ----------
    .. [1] Learning Bounded Treewidth Bayesian Networks.
       Gal Elidan, Stephen Gould; JMLR, 9(Dec):2699--2731, 2008.
       http://jmlr.csail.mit.edu/papers/volume9/elidan08a/elidan08a.pdf
    Input graph is not chordal.   )
r   nxNetworkXErrorZGraphZadd_edgesetr   updateaddr   )r   sttreewidth_boundHZinduced_nodesZtripletuvwnr   r   r   r   V   s(    5





c                 #   s    fddt  D D ]}| dkrNt|dkr>tdt| V  qt| }t|}|	| |h}|h}|rt
|||}|	| || t|||@ }||}t|r|| ||kst|V  |}qxtdqxt|V  qdS )aU  Returns all maximal cliques of a chordal graph.

    The algorithm breaks the graph in connected components and performs a
    maximum cardinality search in each component to get the cliques.

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

    Yields
    ------
    frozenset of nodes
        Maximal cliques, each of which is a frozenset of
        nodes in `G`. The order of cliques is arbitrary.

    Raises
    ------
    NetworkXError
        The algorithm does not support DiGraph, MultiGraph and MultiDiGraph.
        The algorithm can only be applied to chordal graphs. If the input
        graph is found to be non-chordal, a :exc:`NetworkXError` is raised.

    Examples
    --------
    >>> e = [
    ...     (1, 2),
    ...     (1, 3),
    ...     (2, 3),
    ...     (2, 4),
    ...     (3, 4),
    ...     (3, 5),
    ...     (3, 6),
    ...     (4, 5),
    ...     (4, 6),
    ...     (5, 6),
    ...     (7, 8),
    ... ]
    >>> G = nx.Graph(e)
    >>> G.add_node(9)
    >>> cliques = [c for c in chordal_graph_cliques(G)]
    >>> cliques[0]
    frozenset({1, 2, 3})
    c                 3   s   | ]}  | V  qd S N)subgraphcopy).0cr   r   r   	<genexpr>   s     z(chordal_graph_cliques.<locals>.<genexpr>   r   r   N)r   number_of_nodesr   number_of_selfloopsr   	frozensetnodesr   r   remove_max_cardinality_noder   Z	neighborsr%   _is_complete_graph)r   C
unnumberedr!   numberedclique_wanna_beZnew_clique_wanna_besgr   r   r   r      s.    -






c                 C   s<   t | stdd}t| D ]}t|t|}q |d S )a  Returns the treewidth of the chordal graph G.

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

    Returns
    -------
    treewidth : int
        The size of the largest clique in the graph minus one.

    Raises
    ------
    NetworkXError
        The algorithm does not support DiGraph, MultiGraph and MultiDiGraph.
        The algorithm can only be applied to chordal graphs. If the input
        graph is found to be non-chordal, a :exc:`NetworkXError` is raised.

    Examples
    --------
    >>> e = [
    ...     (1, 2),
    ...     (1, 3),
    ...     (2, 3),
    ...     (2, 4),
    ...     (3, 4),
    ...     (3, 5),
    ...     (3, 6),
    ...     (4, 5),
    ...     (4, 6),
    ...     (5, 6),
    ...     (7, 8),
    ... ]
    >>> G = nx.Graph(e)
    >>> G.add_node(9)
    >>> nx.chordal_graph_treewidth(G)
    3

    References
    ----------
    .. [1] https://en.wikipedia.org/wiki/Tree_decomposition#Treewidth
    r   r*   )r   r   r   r   maxr   )r   Z
max_cliqueZcliquer   r   r   r      s    ,
c                 C   sL   t | dkrt d|  }|dk r,dS |  }||d  d }||kS )z&Returns True if G is a complete graph.r   z'Self loop found in _is_complete_graph()r   Tr*   )r   r,   r   r+   Znumber_of_edges)r   r#   eZ	max_edgesr   r   r   r1      s    
r1   c                 C   sH   t | }| D ]6}|t t| |  |g  }|r|| f  S qdS )z5Given a non-complete graph G, returns a missing edge.N)r   listkeyspop)r   r.   r    missingr   r   r   _find_missing_edge,  s
    r>   c                    s<   d}|D ].}t  fdd| | D }||kr|}|}q|S )z`Returns a the node in choices that has more connections in G
    to nodes in wanna_connect.
    r7   c                    s   g | ]}| kr|qS r   r   )r'   ywanna_connectr   r   
<listcomp>;  s      z)_max_cardinality_node.<locals>.<listcomp>)r   )r   choicesrA   Z
max_numberxnumberZmax_cardinality_noder   r@   r   r0   5  s    r0   c                 C   s   t | dkrt dt| }|dkr0t| }|| |h}d}|rt| ||}|| || t| | |@ }| |}t	|rt
|t|}||krt d| qDt|\}	}
|	||
fS qDdS )a'  Given a graph G, starts a max cardinality search
    (starting from s if s is given and from an arbitrary node otherwise)
    trying to find a non-chordal cycle.

    If it does find one, it returns (u,v,w) where u,v,w are the three
    nodes that together with s are involved in the cycle.
    r   r   Nr7   ztreewidth_bound exceeded: r   )r   r,   r   r   r   r/   r0   r   r%   r1   r8   r   r	   r>   )r   r   r   r3   r4   Zcurrent_treewidthr!   r5   r6   r    r"   r   r   r   r   B  s.    




r   c              	      s0  |   }dd |D }t|r(||fS t }dd | D  t| }tt| ddD ]}t| fddd}|	| |||< g }|D ]l}| 
||r|| q |  fd	d
|D }	t||	||g ||r|| |||f q|D ]}
 |
  d7  < qq`|| ||fS )a  Return a copy of G completed to a chordal graph

    Adds edges to a copy of G to create a chordal graph. A graph G=(V,E) is
    called chordal if for each cycle with length bigger than 3, there exist
    two non-adjacent nodes connected by an edge (called a chord).

    Parameters
    ----------
    G : NetworkX graph
        Undirected graph

    Returns
    -------
    H : NetworkX graph
        The chordal enhancement of G
    alpha : Dictionary
            The elimination ordering of nodes of G

    Notes
    -----
    There are different approaches to calculate the chordal
    enhancement of a graph. The algorithm used here is called
    MCS-M and gives at least minimal (local) triangulation of graph. Note
    that this triangulation is not necessarily a global minimum.

    https://en.wikipedia.org/wiki/Chordal_graph

    References
    ----------
    .. [1] Berry, Anne & Blair, Jean & Heggernes, Pinar & Peyton, Barry. (2004)
           Maximum Cardinality Search for Computing Minimal Triangulations of
           Graphs.  Algorithmica. 39. 287-298. 10.1007/s00453-004-1084-3.

    Examples
    --------
    >>> from networkx.algorithms.chordal import complete_to_chordal_graph
    >>> G = nx.wheel_graph(10)
    >>> H, alpha = complete_to_chordal_graph(G)
    c                 S   s   i | ]
}|d qS r   r   r'   noder   r   r   
<dictcomp>  s      z-complete_to_chordal_graph.<locals>.<dictcomp>c                 S   s   i | ]
}|d qS rF   r   rG   r   r   r   rI     s      r   r7   c                    s    |  S r$   r   )rH   )weightr   r   <lambda>      z+complete_to_chordal_graph.<locals>.<lambda>)keyc                    s   g | ]} | k r|qS r   r   rG   rJ   Zy_weightr   r   rB     s     z-complete_to_chordal_graph.<locals>.<listcomp>r*   )r&   r   r   r   r.   r:   ranger   r8   r/   Zhas_edgeappendZhas_pathr%   r   Zadd_edges_from)r   r   alphaZchordsZunnumbered_nodesizZupdate_nodesr?   Zlower_nodesrH   r   rN   r   r
   g  s4    )



)r   sysZnetworkxr   Znetworkx.algorithms.componentsr   Znetworkx.utilsr   r   __all__ZNetworkXExceptionr	   r   maxsizer   r   r   r1   r>   r0   r   r
   r   r   r   r   <module>   s0   
7MH5	%