U
    L_#                     @   sX   d Z ddlmZ ddlmZmZ ddlmZ eeZ	G dd de
ZG dd	 d	eZd
S )z,
Created on Sep 12, 2012

@author: smirarab
   )Job    )ReadonlySubalignmentExtendedAlignment)
get_loggerc                   @   s   e Zd ZdZdd Zdd ZeeZdd ZeeZ	dd	 Z
ee
Z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 )Problema  
    This class gives a hierarchy of Problems. Each problem includes a list
    of subproblems, and a pointer to the __parent problem. Root problem has no
    __parent problem, and tips have empty lists as their __children.

    This class provides the data structure required to decompose a problem
    recursively into subproblems.

    A problem can have many Jobs associated with it. These job objects are kept
    in a dictionary.
    c                 C   sF   g | _ || _|r4t|ts*tdt| ||  t | _i | _	d S )Nz)Expecting Problem but founding %s instead)
_Problem__children_Problem__parent
isinstancer   	TypeErrortype	add_childdictjobsannotations)selfparent r   +lib/python3.8/site-packages/sepp/problem.py__init__   s    

zProblem.__init__c                 C   s   | j S N)r	   r   r   r   r   
get_parent(   s    zProblem.get_parentc                 C   s   | j d krdS | j jd S )Nr   r   )r   levelr   r   r   r   	get_level,   s    zProblem.get_levelc                 C   s   | j S r   )r   r   r   r   r   get_children0   s    zProblem.get_childrenc                 C   s   | j | dS )z"
        Add a child job.
        N)r   append)r   Z
subproblemr   r   r   r   4   s    zProblem.add_childc                 c   s:   t | jdkr| V  n | jD ]}| D ]
}|V  q(qdS )zT
        Returns an iterator over tips of the problem hierarchy below self.
        r   N)lenr   iter_leaves)r   ctipr   r   r   r   :   s
    
zProblem.iter_leavesc                 c   s8   | j |kr| V  n"| jD ]}||D ]
}|V  q&qdS )z
        a generator function, returning all Problems under the current problem,
        with a label tag equal to the given level.

        Note that this is NOT returning nodes that are 'level' levels below
        self.
        N)r   r   iter_nodes_at_level)r   r   r   r    r   r   r   r!   E   s
    

zProblem.iter_nodes_at_levelc                 C   s   || j |< dS )zF
        A a new job to this problem, to be saved with a name
        N)r   )r   jobnamejobr   r   r   add_jobT   s    zProblem.add_jobFc              	   C   s   | j | }|dkrdS t|ts0tdt| |jrt|dr|jrt|j	d}t
| }W 5 Q R X t|j	d}W 5 Q R X |S |j	S ntd|t|f dS )z>
        returns results of a job, given the job name
        Nzjob '%s' is not a Job objectresults_on_temprwz#job '%s' has no results set yet: %s)r   r
   r   AssertionErrorstrZ
result_sethasattrr%   openresultevalread	Exception)r   r"   Zignore_missing_resultsr#   fresr   r   r   get_job_result_by_nameZ   s    


zProblem.get_job_result_by_namec                 C   s   dS )zN
         returns a label for this Problem. Used in __str__ function.
        Nr   r   r   r   r   get_node_labelo   s    zProblem.get_node_labelc                 C   s,   | g}| }|j d k	r(||j  |j }q
|S r   )r   r   )r   Zretnr   r   r   get_path_to_rootu   s    
zProblem.get_path_to_rootc                 O   s8   |   }t| jdkr|S dddd | jD |f S )Nr   z(%s)%s,c                 s   s   | ]}t |V  qd S r   )r)   ).0Zchildr   r   r   	<genexpr>   s     z"Problem.__str__.<locals>.<genexpr>)r3   r   r   join)r   argskwargsmer   r   r   __str__}   s     zProblem.__str__N)F)__name__
__module____qualname____doc__r   r   propertyr   r   r   r   Zchildrenr   r   r!   r$   r2   r3   r5   r=   r   r   r   r   r      s    
r   c                   @   sx   e Zd ZdZdddZdd ZeeZdd Zd	d
 Z	eee	Z
dd Zdd ZeeeZdd Zdd ZdddZdS )SeppProblemaF   A typical Sepp subproblem, defined by a set of taxa, and a parent

        Adds few basic attributes of a Sepp Problem to the Problem class:
        1- a list of taxa associated with this sub problem
        2- a Readonly subalignment of the parent problem's alginemnt, induced
           by this probelms's taxa (with all gaps columns included)
        3- the subtree of parent problem's tree, induced by this problem's
            taxa. This is a deep copy.
        4- a set of fragments associated with this subproblem

        List of taxa is a required field, provided upon initiailzation.
        Subalignment is automatically computed, and cannot be changed.
        Subtree is automatically computed, but can be overwriteen by the user
        Fragments is not automatically computed, and needs to be set by the
        user
    Nc                 C   s.   t | | || _d | _d | _d | _d | _d S r   )r   r   _SeppProblem__taxa_SeppProblem__subalignment_SeppProblem__subtree	fragmentslabel)r   taxar   r   r   r   r      s    zSeppProblem.__init__c                 C   s   | j S r   )rD   r   r   r   r   get_taxa   s    zSeppProblem.get_taxac                 C   sJ   | j dkrDt| jts"t| jdr6t| j| jj| _ ntd| j | j S )z
        If subalignment is not set before, automatically builds a readonly
        subalignment for this subproblem, based on the taxa assigned to this
        subproblem. Otherwise, returns the saves subalignment.
        Nsubalignmentz.parent object %s has no subalignment attribute)	rE   r
   r   rC   r*   r   rI   rK   r   r   r   r   r   get_subalignment   s    
  zSeppProblem.get_subalignmentc                 C   s
   || _ d S r   )rE   )r   Z	alignmentr   r   r   set_subalignment   s    zSeppProblem.set_subalignmentc                 C   sJ   | j dkrDt| jts"t| jdr6| jj| j| _ ntd| j | j S )z
        If subtree is not assigned before, automatically buils a subtree based
        on the taxa assigned to this subproblem. Otherwise, returns the saves
        subtree.
        Nsubtreez)parent object %s has no subtree attribute)	rF   r
   r   rC   r*   rN   get_subtreerI   r   r   r   r   r   rO      s    
 zSeppProblem.get_subtreec                 C   s
   || _ d S r   )rF   )r   rN   r   r   r   set_subtree   s    zSeppProblem.set_subtreec                 C   s   | j S r   )rH   r   r   r   r   r3      s    zSeppProblem.get_node_labelc                 C   s@   | j  }| }|| || jd< td|t|f  |S )a  
        Writes out the subalignment associated with this subproblem to a file,
        removing all gap columns, but also keeping track of what was removed
        and what was kept. This method keeps track of column names that were
        actually written to file, so that later on, column names could be set
        to the original value. This is crucial for a correct merge.
        (see read_extendend_alignment_and_relabel_columns)
        ref.alignment.columnszHsubalignment without allgap columns written to %s; %d columns remaining.)rK   Zget_mutable_alignmentZdelete_all_gapZwrite_to_pathr   _LOGdebugr   )r   pathZ
mut_subalgremaining_colsr   r   r   )write_subalignment_without_allgap_columns   s    	



z5SeppProblem.write_subalignment_without_allgap_columnsTc                 C   sl   | j d }|dk	rt|dks&tdtd||t|f  tt| j }|	||| |
| |S )a  
        This method goes with write_subalignment_without_allgap_columns method.
        It enables reading back an alignment that was previously written to
        disk, and relabeling its columns with the original labels.
        extension_path is a path to an .sto file (or a list of paths).
        Alignments from these .sto files are also read, and merged with the
        original (base) alignment.
        rQ   Nr   zNSubproblem needs to have a proper list of alignment columns associated with itz?Reading %s %s and relabeling it based on %d orig column labels.)r   r   r(   rR   rS   r   listrG   keysZbuild_extended_alignmentZrelabel_original_columns)r   	orig_pathZextension_pathZconvert_to_stringrU   Zap_algr   r   r   ,read_extendend_alignment_and_relabel_columns   s&    


  
z8SeppProblem.read_extendend_alignment_and_relabel_columns)N)T)r>   r?   r@   rA   r   rJ   rB   rI   rL   rM   rK   rO   rP   rN   r3   rV   rZ   r   r   r   r   rC      s   


 rC   N)rA   Z	schedulerr   Zsepp.alignmentr   r   Zseppr   r>   rR   objectr   rC   r   r   r   r   <module>   s   x