def decompose_tree(self, maxSize, strategy, minSize = None, tree_map={}, decomp_strategy = 'normal', pdistance = 1, distances = None): """ This function decomposes the tree until all subtrees are smaller than the max size, but does not decompose below min size. Two possible decompositions strategies can used: "centroid" and "longest". Returns a map containing the subtrees, in an ordered fashion. SIDE EFFECT: deroots the tree (TODO: necessary?) """ #Don't deroot if doing clade-based decomposition if (strategy != 'clade'): self._tree.deroot() else: #If doing clade-based decomp and it's not rooted, root it! if self._tree.is_rooted == False: self._tree.reroot_at_midpoint() if (decomp_strategy == 'hierarchical' and self.count_leaves() > maxSize): tree_map[len(tree_map)] = copy.deepcopy(self) if (self.count_leaves() > maxSize or (pdistance != 1 and get_pdistance(distances, self.leaf_node_names()) > pdistance)): (t1, t2, e) = self.bisect_tree(strategy, minSize) if e is not None: t1.decompose_tree(maxSize, strategy, minSize, tree_map, decomp_strategy, pdistance, distances) t2.decompose_tree(maxSize, strategy, minSize, tree_map, decomp_strategy,pdistance, distances) else: tree_map[len(tree_map)] = self _LOG.warning("It was not possible to break-down the following tree according to given subset sizes: %d , %d:\n %s" %(minSize, maxSize, self._tree)) else: tree_map[len(tree_map)] = self return tree_map
def decompose_tree(self, maxSize, strategy, minSize=None, tree_map={}, decomp_strategy='normal', pdistance=1, distances=None, maxDiam=None): """ This function decomposes the tree until all subtrees are smaller than the max size, but does not decompose below min size. Two possible decompositions strategies can used: "centroid" and "longest". Returns a map containing the subtrees, in an ordered fashion. SIDE EFFECT: deroots the tree (TODO: necessary?) """ def diameter_height(node): if node.is_leaf(): return 0, 0 # print(node.edge.length) ld, lh = diameter_height(node.child_nodes()[0]) rd, rh = diameter_height(node.child_nodes()[1]) print((ld, lh, rd, rh)) return max(lh + rh, ld, rd), max(lh + node.child_nodes()[0].edge.length, rh + node.child_nodes()[1].edge.length) def find_tree_diameter(node): d, _ = diameter_height(node) return d def get_bits(diameter): p = (1 / 4) * (1 + 3 * math.exp(-4 / 3 * diameter)) print(p) return -(p * math.log(p, 2) + 3 * ((1 - p) / 3 * math.log( (1 - p) / 3, 2))) # uym2 added # if (decomp_strategy in ["midpoint", "centroid"]): T = decompose_by_diameter(self._tree, strategy=decomp_strategy, max_size=maxSize, max_diam=maxDiam, min_size=minSize) for i, t in enumerate(T): tree_map[i] = PhylogeneticTree(t) return tree_map ############## # Don't deroot if doing clade-based decomposition if (strategy != 'clade'): self._tree.deroot() else: # If doing clade-based decomp and it's not rooted, root it! if self._tree.is_rooted is False: self._tree.reroot_at_midpoint() if ((decomp_strategy == 'hierarchical') and (self.count_leaves() > maxSize)): # print(find_tree_diameter(self._tree.seed_node)) self.diameter = find_tree_diameter(self._tree.seed_node) if self.diameter: self.bits = get_bits(self.diameter) # self.bits = get_bits(self.diameter) tree_map[len(tree_map)] = copy.deepcopy(self) if ((self.count_leaves() > maxSize) or ((pdistance != 1) and (get_pdistance(distances, self.leaf_node_names()) > pdistance))): (t1, t2, e) = self.bisect_tree(strategy, minSize) if e is not None: t1.decompose_tree(maxSize, strategy, minSize, tree_map, decomp_strategy, pdistance, distances) t2.decompose_tree(maxSize, strategy, minSize, tree_map, decomp_strategy, pdistance, distances) else: tree_map[len(tree_map)] = self _LOG.warning( ("It was not possible to break-down the following tree " "according to given subset sizes: %d , %d:\n %s") % (minSize, maxSize, self._tree)) else: # print(find_tree_diameter(self._tree.seed_node)) self.diameter = find_tree_diameter(self._tree.seed_node) if self.diameter: self.bits = get_bits(self.diameter) tree_map[len(tree_map)] = self return tree_map