Source code for pylogeny.parsimony

''' Toolkit for performance of Parsimonious Criterion (Parsimony) methods of
optimization of a phylogenetic topology with a particular set of data. '''

# Date:   Mar 3 2014
# Author: Alex Safatli
# E-mail: safatli@cs.dal.ca

from base import treeStructure
postorder = treeStructure.postOrderTraversal

[docs]class profile_set: ''' Hold a set of site_profile profiles for an entire alignment. '''
[docs] def __init__(self,alignment): ''' Initialize this profile set by indicating an alignment. :param alignment: an alignment object :type alignment: an :class:`.alignment.alignment` object ''' self.alignment = alignment self.numSites = alignment.getSize() self.taxa = {} self.profiles = [] self.weights = [] self.sites = [] self._constructSet() self._buildTaxaDict()
def _constructSet(self): ''' PRIVATE: Build all site_profiles. ''' num = self.numSites for site in xrange(num): pro = site_profile(self.alignment,site) self.sites.append(pro) if pro in self.profiles: self.weights[self.profiles.index(pro)] += 1 else: self.profiles.append(pro) self.weights.append(1) def _buildTaxaDict(self): ''' PRIVATE: Build taxa dictionary. ''' tax = self.alignment.getTaxa() for t in xrange(len(tax)): self.taxa[tax[t]] = t def __len__(self): return len(self.profiles)
[docs] def weight(self,val): ''' Acquire the weight associated with an index. :param val: an index of the set :type val: an integer :return: a weight (integer) ''' return self.weights[val]
[docs] def get(self,val): ''' Acquire the site profile at an index. :param val: an index of the set :type val: an integer :return: a :class:`.site_profile` object ''' return self.profiles[val]
[docs] def getForTaxa(self,val,tax): ''' Acquire the string of sequence alphabet characters for a taxon. :param val: an index of the set :type val: an integer :param tax: a taxon name :type tax: a string :return: a string of characters ''' return self.profiles[val].vector[self.taxa[tax]]
[docs]class site_profile: ''' Consolidate a single column of the alignment into a set of components with associated counts. '''
[docs] def __init__(self,alignment,site): ''' Initialize this profile. :param alignment: an alignment object :type alignment: an `.alignment.alignment` object :param site: a site/column index along the alignment :type site: an integer ''' self.alignment = alignment self.site = site self.alphabet = None self.vector = '' self._buildVector()
def __eq__(self,o): if (o == None): return False return (self.vector == o.vector) def __ne__(self,o): return not self.__eq__(o) def __str__(self): return self.vector def _buildVector(self): ''' Build the vector comprising the set of components. ''' aliData = self.alignment.data sitesli = aliData.sequenceSlice(self.site) compn = 0 comps = {} for it in sitesli: if not it in comps: comps[it] = compn compn += 1 self.vector += str(comps[it]) self.alphabet = comps
[docs]def fitch_cost(topology,profiles): ''' Calculate the cost using Fitch algorithm on profile set and alignment. Deprecated: Python implementation of the Fitch algorithm; see fitch C++ module for a C++ implementation that is roughly four times faster. ''' # Calculate parsimony score. total = 0 porde = [x for x in postorder(topology.getRoot())] for profile in xrange(len(profiles)): posdata, local = {}, 0 for node in porde: # If is leaf. if (len(node.children) == 0): posdata[node] = profiles.getForTaxa(profile,node.label) # Not a leaf. else: a = posdata[node.children[0].child] b = posdata[node.children[1].child] # Get intersection. X = set(a).intersection(set(b)) # If intersection is nothing... if (len(X) == 0): # Cost goes up, take union. local += 1 X = set(a).union(set(b)) posdata[node] = X total += local*profiles.weight(profile) return total
[docs]def fitch(topology,alignment): ''' Perform the Fitch algorithm on a given tree topology and associated alignment. Deprecated: Python implementation of the Fitch algorithm; see fitch C++ module for a C++ implementation that is roughly four times faster. ''' # Turn alignment sets into profiles. profiles = profile_set(alignment) if (len(profiles) == 0): return None return fitch_cost(topology,profiles)