o
    3ήc*$                     @   s^   d Z ddlZddlmZ ddgZdd Zdd	 Zd
d Zdd Z	dd Z
edddd ZdS )a  
An algorithm for finding if two undirected trees are isomorphic,
and if so returns an isomorphism between the two sets of nodes.

This algorithm uses a routine to tell if two rooted trees (trees with a
specified root node) are isomorphic, which may be independently useful.

This implements an algorithm from:
The Design and Analysis of Computer Algorithms
by Aho, Hopcroft, and Ullman
Addison-Wesley Publishing 1974
Example 3.2 pp. 84-86.

A more understandable version of this algorithm is described in:
Homework Assignment 5
McGill University SOCS 308-250B, Winter 2002
by Matthew Suderman
http://crypto.cs.mcgill.ca/~crepeau/CS250/2004/HW5+.pdf
    N)not_implemented_forrooted_tree_isomorphismtree_isomorphismc                 C   s  t  }d}t | d }||i}||i}|d||  |d||  tt | |D ]\}	\}
}|	||  d ||< |||
 ||  q-tt ||D ]\}	\}
}|	||  d ||< |||
 ||  qPi }| D ]\}}|||< qq| D ]\}}|||< q~||||fS )a?  Create a single digraph dT of free trees t1 and t2
    #   with roots root1 and root2 respectively
    # rename the nodes with consecutive integers
    # so that all nodes get a unique name between both trees

    # our new "fake" root node is 0
    # t1 is numbers from 1 ... n
    # t2 is numbered from n+1 to 2n
       r   )nxDiGraphnumber_of_nodesadd_edge	enumerate	bfs_edgesitems)t1root1t2root2dTnewroot1newroot2namemap1namemap2iv1v2namemapoldnew r   W/tmp/pip-target-vg8gfxp4/lib/python/networkx/algorithms/isomorphism/tree_isomorphism.py
root_trees   s&   

r   c                 C   s6   i }d||< t | |D ]\}}|| d ||< q|S )Nr   r   )r   r   )Grootlevelr   r   r   r   r   assign_levelsJ   s
   r"   c                 C   s8   i }|   D ]\}}||vrg ||< || | q|S N)r   append)levelsLnlevr   r   r   group_by_levelsT   s   r)   c                 C   sP   | |k sJ | | |f tt||  || D ]\}\}}t|||| qd S r#   )r$   r
   zipgenerate_isomorphism)vwMordered_childrenr   xyr   r   r   r+   _   s
   "r+   c                    s  t | sJ t |sJ t| |||\}}}t|d}t| }t|}	dd |D  dd |D dd |D }
t|d ddD ]Z}|	| D ]#}||dkrnt	 fdd	|
|D }tt| \|< |
|< qKt	fd
d	|	| D }d}t|D ]\}\}}|dkr|||d  d kr|d7 }| |< qqEg } | dkr | dkrt||||
 fdd|D }|S )ar  
    Given two rooted trees `t1` and `t2`,
    with roots `root1` and `root2` respectivly
    this routine will determine if they are isomorphic.

    These trees may be either directed or undirected,
    but if they are directed, all edges should flow from the root.

    It returns the isomorphism, a mapping of the nodes of `t1` onto the nodes
    of `t2`, such that two trees are then identical.

    Note that two trees may have more than one isomorphism, and this
    routine just returns one valid mapping.

    Parameters
    ----------
    `t1` :  NetworkX graph
        One of the trees being compared

    `root1` : a node of `t1` which is the root of the tree

    `t2` : undirected NetworkX graph
        The other tree being compared

    `root2` : a node of `t2` which is the root of the tree

    This is a subroutine used to implement `tree_isomorphism`, but will
    be somewhat faster if you already have rooted trees.

    Returns
    -------
    isomorphism : list
        A list of pairs in which the left element is a node in `t1`
        and the right element is a node in `t2`.  The pairs are in
        arbitrary order.  If the nodes in one tree is mapped to the names in
        the other, then trees will be identical. Note that an isomorphism
        will not necessarily be unique.

        If `t1` and `t2` are not isomorphic, then it returns the empty list.
    r   c                 S      i | ]}|d qS )r   r   .0r,   r   r   r   
<dictcomp>       z+rooted_tree_isomorphism.<locals>.<dictcomp>c                 S   r2   r   r   r3   r   r   r   r5      r6   c                 S   r2   r7   r   r3   r   r   r   r5      r6   r   c                 3       | ]	} | |fV  qd S r#   r   )r4   u)labelr   r   	<genexpr>       z*rooted_tree_isomorphism.<locals>.<genexpr>c                 3   r9   r#   r   r3   )ordered_labelsr   r   r<      r=   c                    s    g | ]\}} |  | fqS r   r   )r4   r:   r,   )r   r   r   
<listcomp>   s     z+rooted_tree_isomorphism.<locals>.<listcomp>)r   is_treer   r"   maxvaluesr)   range
out_degreesorted
successorslistr*   r
   r+   )r   r   r   r   r   r   r   r%   hr&   r/   r   r,   sforlabelcurrentolisomorphismr   )r;   r   r>   r   r   g   s6   *

directed
multigraphc                 C   s   t | sJ t |sJ t | t |krg S tdd |  D }tdd | D }||kr6g S t | }t |}t|t|krJg S t|dkr[t| |d ||d S t| |d ||d }t|dkrn|S t| |d ||d S )a1  
    Given two undirected (or free) trees `t1` and `t2`,
    this routine will determine if they are isomorphic.
    It returns the isomorphism, a mapping of the nodes of `t1` onto the nodes
    of `t2`, such that two trees are then identical.

    Note that two trees may have more than one isomorphism, and this
    routine just returns one valid mapping.

    Parameters
    ----------
    t1 : undirected NetworkX graph
        One of the trees being compared

    t2 : undirected NetworkX graph
        The other tree being compared

    Returns
    -------
    isomorphism : list
        A list of pairs in which the left element is a node in `t1`
        and the right element is a node in `t2`.  The pairs are in
        arbitrary order.  If the nodes in one tree is mapped to the names in
        the other, then trees will be identical. Note that an isomorphism
        will not necessarily be unique.

        If `t1` and `t2` are not isomorphic, then it returns the empty list.

    Notes
    -----
    This runs in O(n*log(n)) time for trees with n nodes.
    c                 s       | ]\}}|V  qd S r#   r   r4   r'   dr   r   r   r<          z#tree_isomorphism.<locals>.<genexpr>c                 s   rP   r#   r   rQ   r   r   r   r<      rS   r   r   )r   r@   r   rE   degreecenterlenr   )r   r   degree_sequence1degree_sequence2center1center2attempsr   r   r   r      s$   #

)__doc__networkxr   networkx.utils.decoratorsr   __all__r   r"   r)   r+   r   r   r   r   r   r   <module>   s    /
j