
:>"^X                 @   sf  d  Z  d d l Z d d l Z d d l m Z d d l m Z d d l m Z d d l	 m
 Z
 d d l m Z m Z d d	   Z Gd
 d   d e  Z Gd d   d e  Z e Z Gd d   d e  Z Gd d   d e  Z Gd d   d e  Z Gd d   d e  Z Gd d   d e  Z Gd d   d e  Z Gd d   d e  Z Gd d   d e  Z d S)z*Classes and methods for tree construction.    N)BaseTree)MultipleSeqAlignment)
MatrixInfo)_py3k)ziprangec             C   s"   t  j |   p! t |  t t f  S)zReturn True if is numeric.)r   Z_is_int_or_long
isinstancefloatcomplex)x r   ?/tmp/pip-build-ww9dw3qa/biopython/Bio/Phylo/TreeConstruction.py_is_numeric   s    r   c               @   s|   e  Z d  Z d Z d d d  Z d d   Z d d   Z d	 d
   Z d d d  Z d d   Z	 d d   Z
 d d   Z d S)_Matrixa  Base class for distance matrix or scoring matrix.

    Accepts a list of names and a lower triangular matrix.::

        matrix = [[0],
                  [1, 0],
                  [2, 3, 0],
                  [4, 5, 6, 0]]
        represents the symmetric matrix of
        [0,1,2,4]
        [1,0,3,5]
        [2,3,0,6]
        [4,5,6,0]

    :Parameters:
        names : list
            names of elements, used for indexing
        matrix : list
            nested list of numerical lists in lower triangular format

    Examples
    --------
    >>> from Bio.Phylo.TreeConstruction import _Matrix
    >>> names = ['Alpha', 'Beta', 'Gamma', 'Delta']
    >>> matrix = [[0], [1, 0], [2, 3, 0], [4, 5, 6, 0]]
    >>> m = _Matrix(names, matrix)
    >>> m
    _Matrix(names=['Alpha', 'Beta', 'Gamma', 'Delta'], matrix=[[0], [1, 0], [2, 3, 0], [4, 5, 6, 0]])

    You can use two indices to get or assign an element in the matrix.

    >>> m[1,2]
    3
    >>> m['Beta','Gamma']
    3
    >>> m['Beta','Gamma'] = 4
    >>> m['Beta','Gamma']
    4

    Further more, you can use one index to get or assign a list of elements related to that index.

    >>> m[0]
    [0, 1, 2, 4]
    >>> m['Alpha']
    [0, 1, 2, 4]
    >>> m['Alpha'] = [0, 7, 8, 9]
    >>> m[0]
    [0, 7, 8, 9]
    >>> m[0,1]
    7

    Also you can delete or insert a column&row of elemets by index.

    >>> m
    _Matrix(names=['Alpha', 'Beta', 'Gamma', 'Delta'], matrix=[[0], [7, 0], [8, 4, 0], [9, 5, 6, 0]])
    >>> del m['Alpha']
    >>> m
    _Matrix(names=['Beta', 'Gamma', 'Delta'], matrix=[[0], [4, 0], [5, 6, 0]])
    >>> m.insert('Alpha', [0, 7, 8, 9] , 0)
    >>> m
    _Matrix(names=['Alpha', 'Beta', 'Gamma', 'Delta'], matrix=[[0], [7, 0], [8, 4, 0], [9, 5, 6, 0]])

    Nc             C   s}  t  | t  ra t d d   | D  ra t t |   t |  k rR | |  _ qm t d   n t d   | d k r d d   t d t |   d  D } | |  _	 n t  | t  rmt d	 d   | D  rmt d
 d   d d   | D D  rmt |  t |  k r^d d   | D t t d t |   d   k rO| |  _	 qjt d   qyt d   n t d   d S)zInitialize matrix.

        Arguments are a list of names, and optionally a list of lower
        triangular matrix data (zero matrix used by default).
        c             s   s   |  ] } t  | t  Vq d  S)N)r   str).0sr   r   r   	<genexpr>`   s    z#_Matrix.__init__.<locals>.<genexpr>zDuplicate names foundz#'names' should be a list of stringsNc             S   s   g  |  ] } d  g |  q S)r   r   )r   ir   r   r   
<listcomp>k   s   	 z$_Matrix.__init__.<locals>.<listcomp>   c             s   s   |  ] } t  | t  Vq d  S)N)r   list)r   lr   r   r   r   q   s    c             s   s   |  ] } t  |  Vq d  S)N)r   )r   nr   r   r   r   s   s   c             S   s#   g  |  ] } | D] } |  q q Sr   r   )r   Zsublistitemr   r   r   r   t   s   	 c             S   s   g  |  ] } t  |   q Sr   )len)r   mr   r   r   r   z   s   	 z+'matrix' should be in lower triangle formatz,'names' and 'matrix' should be the same sizez,'matrix' should be a list of numerical lists)
r   r   allr   setnames
ValueError	TypeErrorr   matrix)selfr   r"   r   r   r   __init__Y   s&    (&	2z_Matrix.__init__c                s/  t  | t t f  r d   t  | t  r3 |   nN t  | t  ru |  j k rf  j j |    q t d   n t d     t   d k r t d      f d d   t	 d    D    f d	 d   t	   t    D St |  d
 k rd } d } t
 d d   | D  r5| \ } } n t
 d d   | D  r| \ } } |  j k r|  j k r j j |  }  j j |  } qt d   n t d   | t   d k s| t   d k rt d   | | k r j | | S j | | Sn t d   d S)am  Access value(s) by the index(s) or name(s).

        For a _Matrix object 'dm'::

            dm[i]                   get a value list from the given 'i' to others;
            dm[i, j]                get the value between 'i' and 'j';
            dm['name']              map name to index first
            dm['name1', 'name2']    map name to index first

        NzItem not found.zInvalid index type.r   zIndex out of range.c                s!   g  |  ] }  j    |  q Sr   )r"   )r   r   )indexr#   r   r   r      s   	 z'_Matrix.__getitem__.<locals>.<listcomp>r   c                s!   g  |  ] }  j  |    q Sr   )r"   )r   r   )r%   r#   r   r   r      s   	    c             s   s   |  ] } t  | t  Vq d  S)N)r   int)r   r   r   r   r   r      s    z&_Matrix.__getitem__.<locals>.<genexpr>c             s   s   |  ] } t  | t  Vq d  S)N)r   r   )r   r   r   r   r   r      s    )r   r'   r   r   r%   r    r!   r   
IndexErrorr   r   r"   )r#   r   	row_index	col_indexrow_namecol_namer   )r%   r#   r   __getitem__   s>    	"*,z_Matrix.__getitem__c       	      C   s  t  | t t f  rhd } t  | t  r3 | } nN t  | t  ru | |  j k rf |  j j |  } q t d   n t d   | t |   d k r t d   t  | t	  rYt
 d d   | D  rYt |  t |   k rJx, t d |  D] } | | |  j | | <q WxA t | t |    D] } | | |  j | | <q(Wqet d	   qt d
   n^t |  d k rd } d } t
 d d   | D  r| \ } } n t
 d d   | D  r'| \ } } | |  j k r| |  j k r|  j j |  } |  j j |  } q3t d   n t d   | t |   d k s_| t |   d k rkt d   t |  r| | k r| |  j | | <q| |  j | | <qt d
   n t d   d S)zSet value by the index(s) or name(s).

        Similar to __getitem__::

            dm[1] = [1, 0, 3, 4]    set values from '1' to others;
            dm[i, j] = 2            set the value from 'i' to 'j'

        NzItem not found.zInvalid index type.r   zIndex out of range.c             s   s   |  ] } t  |  Vq d  S)N)r   )r   r   r   r   r   r      s    z&_Matrix.__setitem__.<locals>.<genexpr>r   zValue not the same size.zInvalid value type.r&   c             s   s   |  ] } t  | t  Vq d  S)N)r   r'   )r   r   r   r   r   r      s    c             s   s   |  ] } t  | t  Vq d  S)N)r   r   )r   r   r   r   r   r      s    )r   r'   r   r   r%   r    r!   r   r(   r   r   r   r"   r   )	r#   r   valuer%   r   r)   r*   r+   r,   r   r   r   __setitem__   sN    
	(,z_Matrix.__setitem__c             C   s   d } t  | t  r | } n0 t  | t  rB |  j j |  } n t d   x/ t | d t |    D] } |  j | | =qh W|  j | =|  j | =d S)z.Delete related distances by the index or name.NzInvalid index type.r   )	r   r'   r   r   r%   r!   r   r   r"   )r#   r   r%   r   r   r   r   __delitem__   s    	 
z_Matrix.__delitem__c             C   s   t  | t  r | d k r' t |   } t  | t  sB t d   |  j j | |  |  j j | d g |  x4 t | t |    D] } |  j | j | d  q W| |  | <n t d   d S)zInsert distances given the name and value.

        :Parameters:
            name : str
                name of a row/col to be inserted
            value : list
                a row/col of values to be inserted

        NzInvalid index type.r   zInvalid name type.)	r   r   r   r'   r!   r   insertr"   r   )r#   namer.   r%   r   r   r   r   r1   	  s    
z_Matrix.insertc             C   s   t  |  j  S)zMatrix length.)r   r   )r#   r   r   r   __len__$  s    z_Matrix.__len__c             C   s-   |  j  j d t t t |  j |  j f   S)zReturn Matrix as a string.z(names=%s, matrix=%s))	__class____name__tuplemapreprr   r"   )r#   r   r   r   __repr__(  s    z_Matrix.__repr__c                sO   d j    f d d   t d t     D  } | d d j    j  } | S)z%Get a lower triangular matrix string.
c                sB   g  |  ]8 }   j  | d  d  j d d     j | D   q S)	c             S   s   g  |  ] } t  |   q Sr   )r   )r   r   r   r   r   r   2  s   	 z._Matrix.__str__.<locals>.<listcomp>.<listcomp>)r   joinr"   )r   r   )r#   r   r   r   2  s   	z#_Matrix.__str__.<locals>.<listcomp>r   z
	r;   )r<   r   r   r   )r#   Zmatrix_stringr   )r#   r   __str__.  s
    z_Matrix.__str__)r5   
__module____qualname____doc__r$   r-   r/   r0   r1   r3   r9   r=   r   r   r   r   r      s   ?*6@r   c               @   sI   e  Z d  Z d Z d d d  Z d d   Z d d   Z d	 d
   Z d S)DistanceMatrixzDistance matrix class that can be used for distance based tree algorithms.

    All diagonal elements will be zero no matter what the users provide.
    Nc             C   s!   t  j |  | |  |  j   d S)zInitialize the class.N)r   r$   _set_zero_diagonal)r#   r   r"   r   r   r   r$   @  s    zDistanceMatrix.__init__c             C   s!   t  j |  | |  |  j   d S)zSet Matrix's items to values.N)r   r/   rB   )r#   r   r.   r   r   r   r/   E  s    zDistanceMatrix.__setitem__c             C   s5   x. t  d t |    D] } d |  j | | <q Wd S)z,Set all diagonal elements to zero (PRIVATE).r   N)r   r   r"   )r#   r   r   r   r   rB   J  s    z!DistanceMatrix._set_zero_diagonalc       	         s(  | j  d j t  j    t d t t t  j   d  } d d   t d t  j  d  D } d t |  d d j	 |  d	 } x t
 t  j  j   D]r \   \ } }    f d
 d   t   d t  j   D } t j | g | |  } | j  | j |    q Wd S)a  Write data in Phylip format to a given file-like object or handle.

        The output stream is the input distance matrix format used with Phylip
        programs (e.g. 'neighbor'). See:
        http://evolution.genetics.washington.edu/phylip/doc/neighbor.html

        :Parameters:
            handle : file or file-like object
                A writeable file handle or other object supporting the 'write'
                method, such as StringIO or sys.stdout. On Python 3, should be
                open in text mode.

        z    {0}
   r   c             s   s#   |  ] } d  t  |  d Vq d S){z:.4f}N)r   )r   r   r   r   r   r   `  s    z/DistanceMatrix.format_phylip.<locals>.<genexpr>z{0:zs}z  r:   c             3   s    |  ] }  j  |   Vq d  S)N)r"   )r   j)r   r#   r   r   r   d  s    N)writeformatr   r   maxr7   r   r"   r   r<   	enumerater   	itertoolschain)	r#   handleZ
name_widthZ
value_fmtsZrow_fmtr2   valuesZmirror_valuesfieldsr   )r   r#   r   format_phylipO  s    %)%.2zDistanceMatrix.format_phylip)r5   r>   r?   r@   r$   r/   rB   rO   r   r   r   r   rA   :  s
   rA   c               @   sZ  e  Z d  Z d Z d d d d g Z d g d+ d g d, d- d g d. d/ d0 d g g Z d g d1 d g d2 d3 d g d4 d5 d6 d g g Z d d
 d d d d d d d d d d d d d d d d d d d d d g Z d e d e i Z e	 j
 Z d d    e D Z e e j    Z d! g e e Z d! d" d# d$  Z d% d&   Z d' d(   Z d) d*   Z d" S)7DistanceCalculatora  Class to calculate the distance matrix from a DNA or Protein.

    Multiple Sequence Alignment(MSA) and the given name of the
    substitution model.

    Currently only scoring matrices are used.

    :Parameters:
        model : str
            Name of the model matrix to be used to calculate distance.
            The attribute ``dna_matrices`` contains the available model
            names for DNA sequences and ``protein_matrices`` for protein
            sequences.

    Examples
    --------
    Loading a small PHYLIP alignment from which to compute distances::

        from Bio.Phylo.TreeConstruction import DistanceCalculator
        from Bio import AlignIO
        aln = AlignIO.read(open('TreeConstruction/msa.phy'), 'phylip')
        print(aln)

    Output::

        SingleLetterAlphabet() alignment with 5 rows and 13 columns
        AACGTGGCCACAT Alpha
        AAGGTCGCCACAC Beta
        CAGTTCGCCACAA Gamma
        GAGATTTCCGCCT Delta
        GAGATCTCCGCCC Epsilon

    DNA calculator with 'identity' model::

        calculator = DistanceCalculator('identity')
        dm = calculator.get_distance(aln)
        print(dm)

    Output::

        Alpha	0
        Beta	0.23076923076923073	0
        Gamma	0.3846153846153846	0.23076923076923073	0
        Delta	0.5384615384615384	0.5384615384615384	0.5384615384615384	0
        Epsilon	0.6153846153846154	0.3846153846153846	0.46153846153846156	0.15384615384615385	0
            Alpha	Beta	Gamma	Delta	Epsilon

    Protein calculator with 'blosum62' model::

        calculator = DistanceCalculator('blosum62')
        dm = calculator.get_distance(aln)
        print(dm)

    Output::

        Alpha	0
        Beta	0.36904761904761907	0
        Gamma	0.49397590361445787	0.25	0
        Delta	0.5853658536585367	0.5476190476190477	0.5662650602409638	0
        Epsilon	0.7	0.3555555555555555	0.48888888888888893	0.2222222222222222	0
            Alpha	Beta	Gamma	Delta	Epsilon

    ATCG         r   BDEFHIKLMNPQRSVWXYZblastntransc             C   s"   i  |  ] } t  t |  |  q Sr   )getattrr   )r   r2   r   r   r   
<dictcomp>  s   	 zDistanceCalculator.<dictcomp>identityNc             C   s   | r | |  _  n! | d k r* f  |  _  n	 d |  _  | d k rK d |  _ nu | |  j k ry t |  j |  j |  |  _ nG | |  j k r |  j |  j |  |  _ n t	 d d j
 |  j    d S)z!Initialize with a distance model.ro   -*Nz'Model not supported. Available models: z, )rp   rq   )skip_lettersscoring_matrix
dna_modelsr   dna_alphabetdna_matricesprotein_models_build_protein_matrixprotein_matricesr    r<   models)r#   modelrr   r   r   r   r$     s    	zDistanceCalculator.__init__c       
         s}  d } d }   j  r)d } d } x t d t |   D] } | | } | | }	 |   j k s7 |	   j k rr q7 |   j  j k r t d | | j | f   |	   j  j k r t d |	 | j | f   |   j  | | f 7} |   j  |	 |	 f 7} |   j  | |	 f 7} q7 Wt | |  } n4 t   f d d   t	 | |  D  } t |  } | d k rmd Sd | d | S)zCalculate pairwise distance from two sequences (PRIVATE).

        Returns a value between 0 (identical sequences) and 1 (completely
        different, or seq1 is an empty string.)
        r   z3Bad alphabet '%s' in sequence '%s' at position '%s'c             3   s?   |  ]5 \ } } |   j  k r |   j  k r | | k Vq d  S)N)rr   )r   l1l2)r#   r   r   r     s   	z/DistanceCalculator._pairwise.<locals>.<genexpr>r   g      ?)
rs   r   r   rr   r   r    idrH   sumr   )
r#   seq1seq2scoreZ	max_scoreZ
max_score1Z
max_score2r   r|   r}   r   )r#   r   	_pairwise  s:    	

zDistanceCalculator._pairwisec             C   s   t  | t  s t d   d d   | D } t |  } xB t j | d  D]. \ } } |  j | |  | | j | j f <qM W| S)zReturn a DistanceMatrix for MSA object.

        :Parameters:
            msa : MultipleSeqAlignment
                DNA or Protein multiple sequence alignment.

        z+Must provide a MultipleSeqAlignment object.c             S   s   g  |  ] } | j   q Sr   )r~   )r   r   r   r   r   r   &  s   	 z3DistanceCalculator.get_distance.<locals>.<listcomp>r&   )r   r   r!   rA   rJ   combinationsr   r~   )r#   msar   dmr   r   r   r   r   get_distance  s    &zDistanceCalculator.get_distancec             C   sL   t  |  j  } x6 | j   D]( \ } } | \ } } | | | | f <q W| S)z?Convert matrix from SubsMat format to _Matrix object (PRIVATE).)r   protein_alphabetitems)r#   ZsubsmatZprotein_matrixkvZaa1Zaa2r   r   r   rx   ,  s
    z(DistanceCalculator._build_protein_matrixr   r   r   r   r   r   r   r   r   )r5   r>   r?   r@   ru   rk   rl   r   rv   r   Zavailable_matricesrw   ry   r   keysrt   rz   r$   r   r   rx   r   r   r   r   rP   m  sH   ?00		+rP   c               @   s"   e  Z d  Z d Z d d   Z d S)TreeConstructorz$Base class for all tree constructor.c             C   s   t  d   d S)zvCaller to built the tree from a MultipleSeqAlignment object.

        This should be implemented in subclass.
        zMethod not implemented!N)NotImplementedError)r#   r   r   r   r   
build_tree8  s    zTreeConstructor.build_treeN)r5   r>   r?   r@   r   r   r   r   r   r   5  s   r   c               @   sd   e  Z d  Z d Z d d g Z d d d d  Z d d   Z d	 d
   Z d d   Z d d   Z	 d S)DistanceTreeConstructora	  Distance based tree constructor.

    :Parameters:
        method : str
            Distance tree construction method, 'nj'(default) or 'upgma'.
        distance_calculator : DistanceCalculator
            The distance matrix calculator for multiple sequence alignment.
            It must be provided if ``build_tree`` will be called.

    Examples
    --------
    Loading a small PHYLIP alignment from which to compute distances, and then
    build a upgma Tree::

        from Bio.Phylo.TreeConstruction import DistanceTreeConstructor
        from Bio.Phylo.TreeConstruction import DistanceCalculator
        from Bio import AlignIO
        aln = AlignIO.read(open('TreeConstruction/msa.phy'), 'phylip')
        constructor = DistanceTreeConstructor()
        calculator = DistanceCalculator('identity')
        dm = calculator.get_distance(aln)
        upgmatree = constructor.upgma(dm)
        print(upgmatree)

    Output::

        Tree(rooted=True)
            Clade(branch_length=0, name='Inner4')
                Clade(branch_length=0.18749999999999994, name='Inner1')
                    Clade(branch_length=0.07692307692307693, name='Epsilon')
                    Clade(branch_length=0.07692307692307693, name='Delta')
                Clade(branch_length=0.11057692307692304, name='Inner3')
                    Clade(branch_length=0.038461538461538464, name='Inner2')
                        Clade(branch_length=0.11538461538461536, name='Gamma')
                        Clade(branch_length=0.11538461538461536, name='Beta')
                    Clade(branch_length=0.15384615384615383, name='Alpha')

    Build a NJ Tree::

        njtree = constructor.nj(dm)
        print(njtree)

    Output::

        Tree(rooted=False)
            Clade(branch_length=0, name='Inner3')
                Clade(branch_length=0.18269230769230765, name='Alpha')
                Clade(branch_length=0.04807692307692307, name='Beta')
                Clade(branch_length=0.04807692307692307, name='Inner2')
                    Clade(branch_length=0.27884615384615385, name='Inner1')
                        Clade(branch_length=0.051282051282051266, name='Epsilon')
                        Clade(branch_length=0.10256410256410259, name='Delta')
                    Clade(branch_length=0.14423076923076922, name='Gamma')

    njupgmaNc             C   s   | d k s t  | t  r' | |  _ n t d   t  | t  r] | |  j k r] | |  _ n$ t d | d d j |  j    d S)zInitialize the class.Nz)Must provide a DistanceCalculator object.zBad method: z. Available methods: z, )r   rP   distance_calculatorr!   r   methodsmethodr<   )r#   r   r   r   r   r   r$   {  s    z DistanceTreeConstructor.__init__c             C   se   |  j  rU |  j  j |  } d } |  j d k rB |  j |  } n |  j |  } | St d   d S)z7Construct and return a Tree, Neighbor Joining or UPGMA.Nr   z)Must provide a DistanceCalculator object.)r   r   r   r   r   r!   )r#   r   r   treer   r   r   r     s    	z"DistanceTreeConstructor.build_treec             C   sd  t  | t  s t d   t j |  } d d   | j D } d } d } d } xt |  d k rM| d
 } xi t d t |   D]R } xI t d |  D]8 }	 | | | |	 f k r | | |	 f } | } |	 } q Wq W| | }
 | | } | d 7} t j	 d d t
 |   } | j j |
  | j j |  |
 j   rW| d d	 |
 _ n | d d	 |  j |
  |
 _ | j   r| d d	 | _ n | d d	 |  j |  | _ | | | <| | =xe t d t |   D]N } | | k r| | k r| | | f | | | f d d	 | | | f <qWd t
 |  | j | <| | =qU Wd | _ t j |  S)a  Construct and return an UPGMA tree.

        Constructs and returns an Unweighted Pair Group Method
        with Arithmetic mean (UPGMA) tree.

        :Parameters:
            distance_matrix : DistanceMatrix
                The distance matrix for tree construction.

        z%Must provide a DistanceMatrix object.c             S   s"   g  |  ] } t  j d  |   q S)N)r   Clade)r   r2   r   r   r   r     s   	 z1DistanceTreeConstructor.upgma.<locals>.<listcomp>r   r   NInnerg      ?r&   )r   r   )r   rA   r!   copydeepcopyr   r   r   r   r   r   cladesappendis_terminalbranch_length
_height_ofTree)r#   distance_matrixr   r   min_imin_jinner_countmin_distr   rE   clade1clade2inner_clader   r   r   r   r     sH    




4	zDistanceTreeConstructor.upgmac             C   sm  t  | t  s t d   t j |  } d d   | j D } d g t |  } d } d } d } t |  d k r | d } t j | d d St |  d k rPd } d } | | }	 | | }
 | | | f d	 |	 _	 | | | f |	 j	 |
 _	 t j
 d
 d  } | j j |	  | j j |
  | | d <| d } t j | d d Sxnt |  d k rx{ t d t |   D]d } d | | <x5 t d t |   D] } | | | | | f 7<qW| | t |  d | | <q{W| d | d | d } d } d } xu t d t |   D]^ } xU t d |  D]D } | | | f | | | | } | | k r5| } | } | } q5WqW| | }	 | | }
 | d 7} t j
 d
 d t |   } | j j |	  | j j |
  | | | f | | | | d	 |	 _	 | | | f |	 j	 |
 _	 | | | <| | =xo t d t |   D]X } | | k rC| | k rC| | | f | | | f | | | f d	 | | | f <qCWd t |  | j | <| | =qSWd
 } | d | k rd | d _	 | d | d _	 | d j j | d  | d } n@ | d | d _	 d | d _	 | d j j | d  | d } t j | d d S)zConstruct and return a Neighbor Joining tree.

        :Parameters:
            distance_matrix : DistanceMatrix
                The distance matrix for tree construction.

        z%Must provide a DistanceMatrix object.c             S   s"   g  |  ] } t  j d  |   q S)N)r   r   )r   r2   r   r   r   r     s   	 z.DistanceTreeConstructor.nj.<locals>.<listcomp>r   r   rootedFr&   g       @Nr   )r   r   )r   r   )r   r   )r   rA   r!   r   r   r   r   r   r   r   r   r   r   r   r   )r#   r   r   r   Z	node_distr   r   r   rootr   r   r   r   rE   r   tempr   r   r   r   r     s    





  




)
zDistanceTreeConstructor.njc                sH   d } | j    r | j } n& | t   f d d   | j D  } | S)zECalculate clade height -- the longest path to any terminal (PRIVATE).r   c             3   s   |  ] }   j  |  Vq d  S)N)r   )r   c)r#   r   r   r   I  s    z5DistanceTreeConstructor._height_of.<locals>.<genexpr>)r   r   rH   r   )r#   cladeheightr   )r#   r   r   C  s
    &z"DistanceTreeConstructor._height_of)
r5   r>   r?   r@   r   r$   r   r   r   r   r   r   r   r   r   @  s   7Bgr   c               @   s"   e  Z d  Z d Z d d   Z d S)Scorerz(Base class for all tree scoring methods.c             C   s   t  d   d S)ztCaller to get the score of a tree for the given alignment.

        This should be implemented in subclass.
        zMethod not implemented!N)r   )r#   r   	alignmentr   r   r   	get_scoreS  s    zScorer.get_scoreN)r5   r>   r?   r@   r   r   r   r   r   r   P  s   r   c               @   s"   e  Z d  Z d Z d d   Z d S)TreeSearcherz*Base class for all tree searching methods.c             C   s   t  d   d S)znCaller to search the best tree with a starting tree.

        This should be implemented in subclass.
        zMethod not implemented!N)r   )r#   starting_treer   r   r   r   search^  s    zTreeSearcher.searchN)r5   r>   r?   r@   r   r   r   r   r   r   [  s   r   c               @   sF   e  Z d  Z d Z d d   Z d d   Z d d   Z d d	   Z d
 S)NNITreeSearcherzTree searching with Nearest Neighbor Interchanges (NNI) algorithm.

    :Parameters:
        scorer : ParsimonyScorer
            parsimony scorer to calculate the parsimony score of
            different trees during NNI algorithm.

    c             C   s+   t  | t  r | |  _ n t d   d S)zInitialize the class.zMust provide a Scorer object.N)r   r   scorerr!   )r#   r   r   r   r   r$   p  s    zNNITreeSearcher.__init__c             C   s   |  j  | |  S)a5  Implement the TreeSearcher.search method.

        :Parameters:
           starting_tree : Tree
               starting tree of NNI method.
           alignment : MultipleSeqAlignment
               multiple sequence alignment used to calculate parsimony
               score of different NNI trees.

        )_nni)r#   r   r   r   r   r   r   w  s    zNNITreeSearcher.searchc             C   s   | } xs |  j  j | |  } | } xD |  j |  D]3 } |  j  j | |  } | | k  r4 | } | } q4 W| | k r	 Pq	 W| S)zESearch for the best parsimony tree using the NNI algorithm (PRIVATE).)r   r   _get_neighbors)r#   r   r   Z	best_treeZ
best_scorer   tr   r   r   r   r     s    
zNNITreeSearcher._nnic             C   s  i  } xb | j    D]T } | | j k r | j |  } t |  d k rY | j | | <q | d | | <q Wg  } g  } x| j d d  D]} | | j k r| j d } | j d } | j |  | j |  | j   r| j   r| j d }	 | j d }
 | j d } | j d =| j d =| j j |  | j j |	  t j	 |  } | j |  | j d =| j d =| j j |
  | j j |  t j	 |  } | j |  | j d =| j d =| j j |	  | j j
 d |
  q | | k r q q | j d } | j d } | | } | | j d k r| j d } | j d =| j d =| j j |  | j j |  t j	 |  } | j |  | j d =| j d =| j j |  | j j |  t j	 |  } | j |  | j d =| j d =| j j |  | j j
 d |  q | j d } | j d =| j d =| j j
 d |  | j j |  t j	 |  } | j |  | j d =| j d =| j j
 d |  | j j |  t j	 |  } | j |  | j d =| j d =| j j
 d |  | j j
 d |  q W| S)zmGet all neighbor trees of the given tree (PRIVATE).

        Currently only for binary rooted trees.
        r   r&   orderlevelr   )Zfind_cladesr   get_pathr   get_nonterminalsr   r   r   r   r   r1   )r#   r   parentsr   Z	node_pathZ	neighborsZroot_childsleftrightZ
left_rightZ
right_leftZright_rightZ	temp_treeparentZsisterr   r   r   r     s    


















zNNITreeSearcher._get_neighborsN)r5   r>   r?   r@   r$   r   r   r   r   r   r   r   r   f  s
   r   c               @   s1   e  Z d  Z d Z d d d  Z d d   Z d S)ParsimonyScorera	  Parsimony scorer with a scoring matrix.

    This is a combination of Fitch algorithm and Sankoff algorithm.
    See ParsimonyTreeConstructor for usage.

    :Parameters:
        matrix : _Matrix
            scoring matrix used in parsimony score calculation.

    Nc             C   s2   | s t  | t  r" | |  _ n t d   d S)zInitialize the class.zMust provide a _Matrix object.N)r   r   r"   r!   )r#   r"   r   r   r   r$   	  s    zParsimonyScorer.__init__c             C   s#  | j    s t d   | j s+ | j   | j   } | j d d d    | j   t d d   t | |  D  s t d   d } xt t	 | d   D]y} d } | d	 d	  | f } | t	 |  | d k r q |  j
 st t | d
 d   | D   } x| j d d  D]Y }	 |	 j }
 | |
 d } | |
 d } | | @} | sn| | B} | d } | | |	 <qWnt d  } |  j
 j } t	 |  } i  } xR t t	 |   D]> } | g | } | j | |  } d | | <| | | | <qWx| j d d  D] }	 |	 j }
 | |
 d } | |
 d } g  } x t |  D] } | } | } x~ t |  D]p } |  j
 | | | | f | | } |  j
 | | | | f | | } | | k r| } | | k rn| } qnW| j | |  qOW| | |	 <qWt |  } | | } q W| S)zCalculate parsimony score using the Fitch algorithm.

        Calculate and return the parsimony score given a tree and the
        MSA using either the Fitch algorithm (without a penalty matrix)
        or the Sankoff algorithm (with a matrix).
        z(The tree provided should be bifurcating.keyc             S   s   |  j  S)N)r2   )Ztermr   r   r   <lambda>  s    z+ParsimonyScorer.get_score.<locals>.<lambda>c             s   s'   |  ] \ } } | j  | j k Vq d  S)N)r2   r~   )r   r   ar   r   r   r      s    z,ParsimonyScorer.get_score.<locals>.<genexpr>zDTaxon names of the input tree should be the same with the alignment.r   Nc             S   s   g  |  ] } | h  q Sr   r   )r   r   r   r   r   r   4  s   	 z-ParsimonyScorer.get_score.<locals>.<listcomp>r   Z	postorderr   inf)Zis_bifurcatingr    r   Zroot_at_midpointZget_terminalssortr   r   r   r   r"   dictr   r   r	   r   r%   r   min)r#   r   r   Ztermsr   r   Zscore_iZcolumn_iZclade_statesr   Zclade_childsZ
left_stateZright_statestater   ZalphabetlengthZclade_scoresrE   arrayr%   Z
left_scoreZright_scorer   Zmin_lZmin_rr   slsrr   r   r   r     sp    	

"		"	



	##
zParsimonyScorer.get_score)r5   r>   r?   r@   r$   r   r   r   r   r   r     s   
r   c               @   s1   e  Z d  Z d Z d d d  Z d d   Z d S)ParsimonyTreeConstructora0	  Parsimony tree constructor.

    :Parameters:
        searcher : TreeSearcher
            tree searcher to search the best parsimony tree.
        starting_tree : Tree
            starting tree provided to the searcher.

    Examples
    --------
    We will load an alignment, and then load various trees which have already been computed from it::

        from Bio import AlignIO, Phylo
        aln = AlignIO.read(open('TreeConstruction/msa.phy'), 'phylip')
        print(aln)

    Output::

        SingleLetterAlphabet() alignment with 5 rows and 13 columns
        AACGTGGCCACAT Alpha
        AAGGTCGCCACAC Beta
        CAGTTCGCCACAA Gamma
        GAGATTTCCGCCT Delta
        GAGATCTCCGCCC Epsilon

    Load a starting tree::

        starting_tree = Phylo.read('TreeConstruction/nj.tre', 'newick')
        print(starting_tree)

    Output::

        Tree(rooted=False, weight=1.0)
            Clade(branch_length=0.0, name='Inner3')
                Clade(branch_length=0.01421, name='Inner2')
                    Clade(branch_length=0.23927, name='Inner1')
                        Clade(branch_length=0.08531, name='Epsilon')
                        Clade(branch_length=0.13691, name='Delta')
                    Clade(branch_length=0.2923, name='Alpha')
                Clade(branch_length=0.07477, name='Beta')
                Clade(branch_length=0.17523, name='Gamma')

    Build the Parsimony tree from the starting tree::

        scorer = Phylo.TreeConstruction.ParsimonyScorer()
        searcher = Phylo.TreeConstruction.NNITreeSearcher(scorer)
        constructor = Phylo.TreeConstruction.ParsimonyTreeConstructor(searcher, starting_tree)
        pars_tree = constructor.build_tree(aln)
        print(pars_tree)

    Output::

        Tree(rooted=True, weight=1.0)
            Clade(branch_length=0.0)
                Clade(branch_length=0.19732999999999998, name='Inner1')
                    Clade(branch_length=0.13691, name='Delta')
                    Clade(branch_length=0.08531, name='Epsilon')
                Clade(branch_length=0.04194000000000003, name='Inner2')
                    Clade(branch_length=0.01421, name='Inner3')
                        Clade(branch_length=0.17523, name='Gamma')
                        Clade(branch_length=0.07477, name='Beta')
                    Clade(branch_length=0.2923, name='Alpha')

    Nc             C   s   | |  _  | |  _ d S)zInitialize the class.N)searcherr   )r#   r   r   r   r   r   r$     s    	z!ParsimonyTreeConstructor.__init__c             C   sL   |  j  d k r6 t t d  d  } | j |  |  _  |  j j |  j  |  S)zBuild the tree.

        :Parameters:
            alignment : MultipleSeqAlignment
                multiple sequence alignment to calculate parsimony tree.

        Nro   r   )r   r   rP   r   r   r   )r#   r   Zdtcr   r   r   r     s    
z#ParsimonyTreeConstructor.build_tree)r5   r>   r?   r@   r$   r   r   r   r   r   r   c  s   @r   )r@   rJ   r   Z	Bio.Phylor   Z	Bio.Alignr   ZBio.SubsMatr   ZBior   Z	Bio._py3kr   r   r   objectr   rA   Z_DistanceMatrixrP   r   r   r   r   r   r   r   r   r   r   r   <module>   s*    #0 f