3
dZ                 @   sp   d dl Z d dlmZmZ d dlmZ d dlmZ G dd deedZG dd	 d	eZ	G d
d deZ
d	dgZdS )    N)ABCMetaabstractmethod)Tree)slice_boundsc                   s   e Zd ZdZd" fdd	Zed#ddZedd	 Z fd
dZ fddZ	 fddZ
 fddZ fddZd% fdd	Z fddZeedrdd Zdd Zdd Zd d! Z  ZS )&AbstractParentedTreea  
    An abstract base class for a ``Tree`` that automatically maintains
    pointers to parent nodes.  These parent pointers are updated
    whenever any change is made to a tree's structure.  Two subclasses
    are currently defined:

      - ``ParentedTree`` is used for tree structures where each subtree
        has at most one parent.  This class should be used in cases
        where there is no"sharing" of subtrees.

      - ``MultiParentedTree`` is used for tree structures where a
        subtree may have zero or more parents.  This class should be
        used in cases where subtrees may be shared.

    Subclassing
    ===========
    The ``AbstractParentedTree`` class redefines all operations that
    modify a tree's structure to call two methods, which are used by
    subclasses to update parent information:

      - ``_setparent()`` is called whenever a new child is added.
      - ``_delparent()`` is called whenever a child is removed.
    Nc                sv   t  j|| |d k	rrx.t| D ]"\}}t|tr | j||dd q W x*t| D ]\}}t|trP| j|| qPW d S )NT)dry_run)super__init__	enumerate
isinstancer   
_setparent)selfnodechildrenichild)	__class__ 2/tmp/pip-build-v9q4h5k9/nltk/nltk/tree/parented.pyr	   .   s    

zAbstractParentedTree.__init__Fc             C   s   dS )a  
        Update the parent pointer of ``child`` to point to ``self``.  This
        method is only called if the type of ``child`` is ``Tree``;
        i.e., it is not called when adding a leaf to a tree.  This method
        is always called before the child is actually added to the
        child list of ``self``.

        :type child: Tree
        :type index: int
        :param index: The index of ``child`` in ``self``.
        :raise TypeError: If ``child`` is a tree with an impropriate
            type.  Typically, if ``child`` is a tree, then its type needs
            to match the type of ``self``.  This prevents mixing of
            different tree types (single-parented, multi-parented, and
            non-parented).
        :param dry_run: If true, the don't actually set the child's
            parent pointer; just check for any error conditions, and
            raise an exception if one is found.
        Nr   )r   r   indexr   r   r   r   r   @   s    zAbstractParentedTree._setparentc             C   s   dS )a  
        Update the parent pointer of ``child`` to not point to self.  This
        method is only called if the type of ``child`` is ``Tree``; i.e., it
        is not called when removing a leaf from a tree.  This method
        is always called before the child is actually removed from the
        child list of ``self``.

        :type child: Tree
        :type index: int
        :param index: The index of ``child`` in ``self``.
        Nr   )r   r   r   r   r   r   
_delparentV   s    zAbstractParentedTree._delparentc                s0  t |tr`t| |dd\}}}x2t|||D ]"}t | | tr,| j| | | q,W t j| nt |tr|dk r~|t	| 7 }|dk rt
dt | | tr| j| | | t j| nrt |ttfrt	|dkrt
dn.t	|dkr| |d = n| |d  |dd  = ntdt| jt|jf d S )NT)
allow_stepr   zindex out of rangez(The tree position () may not be deleted.   z#%s indices must be integers, not %s)r   slicer   ranger   r   r   __delitem__intlen
IndexErrorlisttuple	TypeErrortype__name__)r   r   startstopstepr   )r   r   r   r   j   s.    


z AbstractParentedTree.__delitem__c                s  t |trt| |dd\}}}t |ttfs4t|}x6t|D ]*\}}t |tr>| j||||  dd q>W x2t|||D ]"}t | | trz| j	| | | qzW x2t|D ]&\}}t |tr| j||||   qW t
 j|| nt |trt|dk r|t| 7 }|dk rtd|| | kr,d S t |trD| j|| t | | trd| j	| | | t
 j|| nzt |ttfrt|dkrtdn4t|dkr|| |d < n|| |d  |dd  < ntdt| jt|jf d S )	NT)r   )r   r   zindex out of rangez,The tree position () may not be assigned to.r   z#%s indices must be integers, not %s)r   r   r   r   r    r
   r   r   r   r   r   __setitem__r   r   r   r!   r"   r#   )r   r   valuer$   r%   r&   r   r   )r   r   r   r'      sF    





z AbstractParentedTree.__setitem__c                s*   t |tr| j|t|  t j| d S )N)r   r   r   r   r   append)r   r   )r   r   r   r)      s    
zAbstractParentedTree.appendc                s8   x2|D ]*}t |tr$| j|t|  t j| qW d S )N)r   r   r   r   r   r)   )r   r   r   )r   r   r   extend   s    

zAbstractParentedTree.extendc                sH   |dk r|t | 7 }|dk r d}t|tr6| j|| t j|| d S )Nr   )r   r   r   r   r   insert)r   r   r   )r   r   r   r+      s    
zAbstractParentedTree.insertr   c                sN   |dk r|t | 7 }|dk r$tdt| | trB| j| | | t j|S )Nr   zindex out of range)r   r   r   r   r   r   pop)r   r   )r   r   r   r,      s    zAbstractParentedTree.popc                s8   | j |}t| | tr(| j| | | t j| d S )N)r   r   r   r   r   remove)r   r   r   )r   r   r   r-      s    
zAbstractParentedTree.remove__getslice__c             C   s   | j ttd|td|S )Nr   )__getitem__r   max)r   r$   r%   r   r   r   r.      s    z!AbstractParentedTree.__getslice__c             C   s   | j ttd|td|S )Nr   )r   r   r0   )r   r$   r%   r   r   r   __delslice__  s    z!AbstractParentedTree.__delslice__c             C   s   | j ttd|td||S )Nr   )r'   r   r0   )r   r$   r%   r(   r   r   r   __setslice__  s    z!AbstractParentedTree.__setslice__c             C   s   | j t| fS )a  Method used by the pickle module when un-pickling.
        This method provides the arguments passed to ``__new__``
        upon un-pickling. Without this method, ParentedTree instances
        cannot be pickled and unpickled in Python 3.7+ onwards.

        :return: Tuple of arguments for ``__new__``, i.e. the label
            and the children of this node.
        :rtype: Tuple[Any, List[AbstractParentedTree]]
        )Z_labelr   )r   r   r   r   __getnewargs__  s    
z#AbstractParentedTree.__getnewargs__)N)F)r4   )r#   
__module____qualname____doc__r	   r   r   r   r   r'   r)   r*   r+   r,   r-   hasattrr   r.   r1   r2   r3   __classcell__r   r   )r   r   r      s"   (<
r   )	metaclassc                   sz   e Zd ZdZd fdd	Zdd Zd fdd		Zd
d Zdd Zdd Z	dd Z
dd Zdd Zdd ZdddZ  ZS )ParentedTreea  
    A ``Tree`` that automatically maintains parent pointers for
    single-parented trees.  The following are methods for querying
    the structure of a parented tree: ``parent``, ``parent_index``,
    ``left_sibling``, ``right_sibling``, ``root``, ``treeposition``.

    Each ``ParentedTree`` may have at most one parent.  In
    particular, subtrees may not be shared.  Any attempt to reuse a
    single ``ParentedTree`` as a child of more than one parent (or
    as multiple children of the same parent) will cause a
    ``ValueError`` exception to be raised.

    ``ParentedTrees`` should never be used in the same tree as ``Trees``
    or ``MultiParentedTrees``.  Mixing tree implementations may result
    in incorrect parent pointers and in ``TypeError`` exceptions.
    Nc                sR   d | _ t j|| |d krNx0t| D ]$\}}t|tr&d |_ | j|| q&W d S )N)_parentr   r	   r
   r   r   r   )r   r   r   r   r   )r   r   r   r	   '  s    
zParentedTree.__init__c             C   s   ddl m} |S )Nr   )ImmutableParentedTree)nltk.tree.immutabler=   )r   r=   r   r   r   _frozen_class5  s    zParentedTree._frozen_classFc                s&   |st j| jj d t jddS )NzB objects do not support shallow copies. Defaulting to a deep copy.T)deep)warningswarnr   r#   r   copy)r   r@   )r   r   r   rC   :  s    zParentedTree.copyc             C   s   | j S )z5The parent of this tree, or None if it has no parent.)r<   )r   r   r   r   parentE  s    zParentedTree.parentc             C   sB   | j dkrdS x"t| j D ]\}}|| kr|S qW ds>tddS )aD  
        The index of this tree in its parent.  I.e.,
        ``ptree.parent()[ptree.parent_index()] is ptree``.  Note that
        ``ptree.parent_index()`` is not necessarily equal to
        ``ptree.parent.index(ptree)``, since the ``index()`` method
        returns the first child that is equal to its argument.
        NFz&expected to find self in self._parent!)r<   r
   AssertionError)r   r   r   r   r   r   parent_indexI  s    
zParentedTree.parent_indexc             C   s(   | j  }| jr$|dkr$| j|d  S dS )z6The left sibling of this tree, or None if it has none.r   r   N)rF   r<   )r   rF   r   r   r   left_siblingX  s    zParentedTree.left_siblingc             C   s2   | j  }| jr.|t| jd k r.| j|d  S dS )z7The right sibling of this tree, or None if it has none.r   N)rF   r<   r   )r   rF   r   r   r   right_sibling_  s    zParentedTree.right_siblingc             C   s"   | }x|j  dk	r|j  }qW |S )z
        The root of this tree.  I.e., the unique ancestor of this tree
        whose parent is None.  If ``ptree.parent()`` is None, then
        ``ptree`` is its own root.
        N)rD   )r   rootr   r   r   rI   f  s    zParentedTree.rootc             C   s*   | j  dkrf S | j  j | j f S dS )z
        The tree position of this tree, relative to the root of the
        tree.  I.e., ``ptree.root[ptree.treeposition] is ptree``.
        N)rD   treepositionrF   )r   r   r   r   rJ   q  s    zParentedTree.treepositionc             C   s6   t |tst| | |kst|j| ks,td |_d S )N)r   r;   rE   r<   )r   r   r   r   r   r   r     s    zParentedTree._delparentc             C   s<   t |tstdt|dr.|jd k	r.td|s8| |_d S )Nz5Can not insert a non-ParentedTree into a ParentedTreer<   z3Can not insert a subtree that already has a parent.)r   r;   r!   r8   r<   
ValueError)r   r   r   r   r   r   r   r     s    
zParentedTree._setparent)N)F)F)r#   r5   r6   r7   r	   r?   rC   rD   rF   rG   rH   rI   rJ   r   r   r9   r   r   )r   r   r;     s   	r;   c                   s|   e Zd ZdZd fdd	Zdd Zdd Zd	d
 Zdd Zdd Z	dd Z
dd Zdd Zdd Zdd ZdddZ  ZS )MultiParentedTreea  
    A ``Tree`` that automatically maintains parent pointers for
    multi-parented trees.  The following are methods for querying the
    structure of a multi-parented tree: ``parents()``, ``parent_indices()``,
    ``left_siblings()``, ``right_siblings()``, ``roots``, ``treepositions``.

    Each ``MultiParentedTree`` may have zero or more parents.  In
    particular, subtrees may be shared.  If a single
    ``MultiParentedTree`` is used as multiple children of the same
    parent, then that parent will appear multiple times in its
    ``parents()`` method.

    ``MultiParentedTrees`` should never be used in the same tree as
    ``Trees`` or ``ParentedTrees``.  Mixing tree implementations may
    result in incorrect parent pointers and in ``TypeError`` exceptions.
    Nc                sR   g | _ t j|| |d krNx0t| D ]$\}}t|tr&g |_ | j|| q&W d S )N)_parentsr   r	   r
   r   r   r   )r   r   r   r   r   )r   r   r   r	     s    
zMultiParentedTree.__init__c             C   s   ddl m} |S )Nr   )ImmutableMultiParentedTree)r>   rN   )r   rN   r   r   r   r?     s    zMultiParentedTree._frozen_classc             C   s
   t | jS )a  
        The set of parents of this tree.  If this tree has no parents,
        then ``parents`` is the empty set.  To check if a tree is used
        as multiple children of the same parent, use the
        ``parent_indices()`` method.

        :type: list(MultiParentedTree)
        )r   rM   )r   r   r   r   parents  s    	zMultiParentedTree.parentsc             C   s   dd | j  D S )a}  
        A list of all left siblings of this tree, in any of its parent
        trees.  A tree may be its own left sibling if it is used as
        multiple contiguous children of the same parent.  A tree may
        appear multiple times in this list if it is the left sibling
        of this tree with respect to multiple parents.

        :type: list(MultiParentedTree)
        c             S   s$   g | ]\}}|d kr||d  qS )r   r   r   ).0rD   r   r   r   r   
<listcomp>  s   z3MultiParentedTree.left_siblings.<locals>.<listcomp>)_get_parent_indices)r   r   r   r   left_siblings  s    zMultiParentedTree.left_siblingsc             C   s   dd | j  D S )a  
        A list of all right siblings of this tree, in any of its parent
        trees.  A tree may be its own right sibling if it is used as
        multiple contiguous children of the same parent.  A tree may
        appear multiple times in this list if it is the right sibling
        of this tree with respect to multiple parents.

        :type: list(MultiParentedTree)
        c             S   s,   g | ]$\}}|t |d  k r||d   qS )r   )r   )rP   rD   r   r   r   r   rQ     s   z4MultiParentedTree.right_siblings.<locals>.<listcomp>)rR   )r   r   r   r   right_siblings  s    z MultiParentedTree.right_siblingsc                s    fdd j D S )Nc                s.   g | ]&}t |D ]\}}| kr||fqqS r   )r
   )rP   rD   r   r   )r   r   r   rQ     s   z9MultiParentedTree._get_parent_indices.<locals>.<listcomp>)rM   )r   r   )r   r   rR     s    
z%MultiParentedTree._get_parent_indicesc             C   s   t | ji j S )z
        The set of all roots of this tree.  This set is formed by
        tracing all possible parent paths until trees with no parents
        are found.

        :type: list(MultiParentedTree)
        )r   _get_roots_helpervalues)r   r   r   r   roots  s    zMultiParentedTree.rootsc             C   s2   | j r"x&| j D ]}|j| qW n| |t| < |S )N)rM   rU   id)r   resultrD   r   r   r   rU     s
    z#MultiParentedTree._get_roots_helperc                s(   | j krg S  fddt|D S dS )aY  
        Return a list of the indices where this tree occurs as a child
        of ``parent``.  If this child does not occur as a child of
        ``parent``, then the empty list is returned.  The following is
        always true::

          for parent_index in ptree.parent_indices(parent):
              parent[parent_index] is ptree
        c                s   g | ]\}}| kr|qS r   r   )rP   r   r   )r   r   r   rQ     s    z4MultiParentedTree.parent_indices.<locals>.<listcomp>N)rM   r
   )r   rD   r   )r   r   parent_indices  s    

z MultiParentedTree.parent_indicesc                s(    krf gS  fddj D S dS )a  
        Return a list of all tree positions that can be used to reach
        this multi-parented tree starting from ``root``.  I.e., the
        following is always true::

          for treepos in ptree.treepositions(root):
              root[treepos] is ptree
        c                s@   g | ]8}|j  D ](}t|D ]\}}|kr||f qqqS r   )treepositionsr
   )rP   rD   Ztreeposr   r   )rI   r   r   r   rQ   "  s   z3MultiParentedTree.treepositions.<locals>.<listcomp>N)rM   )r   rI   r   )rI   r   r   r[     s    	zMultiParentedTree.treepositionsc                sv   t |tst | |kstt fdd|jD dks>tx2t D ]\}}||krH||krHP qHW |jj  d S )Nc                s   g | ]}| kr|qS r   r   )rP   p)r   r   r   rQ   1  s    z0MultiParentedTree._delparent.<locals>.<listcomp>r   )r   rL   rE   r   rM   r
   r-   )r   r   r   r   cr   )r   r   r   -  s     zMultiParentedTree._delparentFc             C   s@   t |tstd|s<x$|jD ]}|| krP qW |jj|  d S )Nz?Can not insert a non-MultiParentedTree into a MultiParentedTree)r   rL   r!   rM   r)   )r   r   r   r   rD   r   r   r   r   ;  s    
zMultiParentedTree._setparent)N)F)r#   r5   r6   r7   r	   r?   rO   rS   rT   rR   rW   rU   rZ   r[   r   r   r9   r   r   )r   r   rL     s   	
rL   )rA   abcr   r   Znltk.tree.treer   Z	nltk.utilr   r   r;   rL   __all__r   r   r   r   <module>   s       7