def test_env_unique_fraction(self): """should report unique fraction of bl in each env """ # testing old unique fraction cur_count_array = self.count_array.copy() bound_indices = bind_to_array(self.nodes, cur_count_array) total_bl = sum(self.branch_lengths) bool_descendants(bound_indices) env_bl_sums, env_bl_ufracs = env_unique_fraction( self.branch_lengths, cur_count_array) # env A has 0 unique bl, B has 4, C has 1 self.assertEqual(env_bl_sums, [0, 4, 1]) self.assertEqual(env_bl_ufracs, [0, 4 / 17.0, 1 / 17.0]) cur_count_array = self.old_count_array.copy() bound_indices = bind_to_array(self.old_nodes, cur_count_array) total_bl = sum(self.old_branch_lengths) bool_descendants(bound_indices) env_bl_sums, env_bl_ufracs = env_unique_fraction( self.old_branch_lengths, cur_count_array) # env A has 0 unique bl, B has 4, C has 1 self.assertEqual(env_bl_sums, env_bl_sums) self.assertEqual(env_bl_sums, [1.29, 0.33999999999999997, 0.63]) self.assertEqual(env_bl_ufracs, [1.29 / 2.9, 0.33999999999999997 / 2.9, 0.63 / 2.9])
def test_fitch_descendants_missing_data(self): """fitch_descendants should work with missing data""" #tree and envs for testing missing values t_str = '(((a:1,b:2):4,(c:3,d:1):2):1,(e:2,f:1):3);' env_str = """a A b B c D d C e C f D""" t = DndParser(t_str, UniFracTreeNode) node_index, nodes = index_tree(t) env_counts = count_envs(env_str.split('\n')) count_array, unique_envs, env_to_index, node_to_index = \ index_envs(env_counts, node_index) branch_lengths = get_branch_lengths(node_index) #test just the AB pair ab_counts = count_array[:, 0:2] bindings = bind_to_array(nodes, ab_counts) changes = fitch_descendants(bindings, counter=FitchCounter) self.assertEqual(changes, 1) orig_result = ab_counts.copy() #check that the original Fitch counter gives the expected #incorrect parsimony result changes = fitch_descendants(bindings, counter=FitchCounterDense) self.assertEqual(changes, 5) new_result = ab_counts.copy() #check that the two versions fill the array with the same values self.assertEqual(orig_result, new_result)
def test_weighted_one_sample(self): """weighted one sample should match weighted matrix""" #should match web site calculations envs = self.count_array bound_indices = bind_to_array(self.nodes, envs) sum_descendants(bound_indices) bl = self.branch_lengths tip_indices = [n._leaf_index for n in self.t.tips()] result = weighted_unifrac_matrix(bl, envs, tip_indices) for i in range(len(result)): one_sam_res = weighted_one_sample(i, bl, envs, tip_indices) self.assertEqual(result[i], one_sam_res) self.assertEqual(result[:, i], one_sam_res) #should work with branch length corrections td = bl.copy()[:, newaxis] tip_bindings = bind_to_parent_array(self.t, td) tips = [n._leaf_index for n in self.t.tips()] tip_distances(td, tip_bindings, tips) result = weighted_unifrac_matrix(bl, envs, tip_indices, bl_correct=True, tip_distances=td) for i in range(len(result)): one_sam_res = weighted_one_sample(i, bl, envs, tip_indices, bl_correct=True, tip_distances=td) self.assertEqual(result[i], one_sam_res) self.assertEqual(result[:, i], one_sam_res)
def test_weighted_unifrac_matrix(self): """weighted unifrac matrix should ret correct results for model tree""" # should match web site calculations envs = self.count_array bound_indices = bind_to_array(self.nodes, envs) sum_descendants(bound_indices) bl = self.branch_lengths tip_indices = [n._leaf_index for n in self.t.tips()] result = weighted_unifrac_matrix(bl, envs, tip_indices) exp = array([[0, 9.1, 4.5], [9.1, 0, 6.4], [4.5, 6.4, 0]]) assert (abs(result - exp)).max() < 0.001 # should work with branch length corrections td = bl.copy()[:, newaxis] tip_bindings = bind_to_parent_array(self.t, td) tips = [n._leaf_index for n in self.t.tips()] tip_distances(td, tip_bindings, tips) result = weighted_unifrac_matrix(bl, envs, tip_indices, bl_correct=True, tip_distances=td) exp = array( [ [0, 9.1 / 11.5, 4.5 / (10.5 + 1.0 / 3)], [9.1 / 11.5, 0, 6.4 / (11 + 1.0 / 3)], [4.5 / (10.5 + 1.0 / 3), 6.4 / (11 + 1.0 / 3), 0], ] ) assert (abs(result - exp)).max() < 0.001
def test_fitch_descendants(self): """fitch_descendants should assign states by fitch parsimony, ret. #""" id_, child = index_tree(self.t3) a = zeros((11, 3)) + 99 # fill with junk bindings = bind_to_array(child, a) # load in leaf envs a[0] = a[1] = a[2] = a[7] = [0, 1, 0] a[3] = [1, 0, 0] a[6] = [0, 0, 1] changes = fitch_descendants(bindings) self.assertEqual(changes, 2) self.assertEqual( a, array( [ [0, 1, 0], [0, 1, 0], [0, 1, 0], [1, 0, 0], [0, 1, 0], [1, 0, 0], [0, 0, 1], [0, 1, 0], [1, 1, 0], [0, 1, 1], [0, 1, 0], ] ), )
def test_bool_descendants(self): """bool_descendants should be true if any descendant true""" # self.t3 = DndParser('(((a,b,c),(d)),(e,f))', UniFracTreeNode) id_, child = index_tree(self.t3) a = zeros((11, 3)) + 99 # fill with junk bindings = bind_to_array(child, a) # load in leaf envs a[0] = a[1] = a[2] = a[7] = [0, 1, 0] a[3] = [1, 0, 0] a[6] = [0, 0, 1] bool_descendants(bindings) self.assertEqual( a, array( [ [0, 1, 0], [0, 1, 0], [0, 1, 0], [1, 0, 0], [0, 1, 0], [1, 0, 0], [0, 0, 1], [0, 1, 0], [1, 1, 0], [0, 1, 1], [1, 1, 1], ] ), )
def test_sum_descendants(self): """sum_descendants should sum total descendants w/ each state""" id_, child = index_tree(self.t3) a = zeros((11, 3)) + 99 # fill with junk bindings = bind_to_array(child, a) # load in leaf envs a[0] = a[1] = a[2] = a[7] = [0, 1, 0] a[3] = [1, 0, 0] a[6] = [0, 0, 1] sum_descendants(bindings) self.assertEqual( a, array( [ [0, 1, 0], [0, 1, 0], [0, 1, 0], [1, 0, 0], [0, 3, 0], [1, 0, 0], [0, 0, 1], [0, 1, 0], [1, 3, 0], [0, 1, 1], [1, 4, 1], ] ), )
def test_weighted_one_sample(self): """weighted one sample should match weighted matrix""" #should match web site calculations envs = self.count_array bound_indices = bind_to_array(self.nodes, envs) sum_descendants(bound_indices) bl = self.branch_lengths tip_indices = [n._leaf_index for n in self.t.tips()] result = weighted_unifrac_matrix(bl, envs, tip_indices) for i in range(len(result)): one_sam_res = weighted_one_sample(i, bl, envs, tip_indices) self.assertEqual(result[i], one_sam_res) self.assertEqual(result[:,i], one_sam_res) #should work with branch length corrections td = bl.copy()[:,newaxis] tip_bindings = bind_to_parent_array(self.t, td) tips = [n._leaf_index for n in self.t.tips()] tip_distances(td, tip_bindings, tips) result = weighted_unifrac_matrix(bl, envs, tip_indices, bl_correct=True, tip_distances=td) for i in range(len(result)): one_sam_res = weighted_one_sample(i, bl, envs, tip_indices, bl_correct=True, tip_distances=td) self.assertEqual(result[i], one_sam_res) self.assertEqual(result[:,i], one_sam_res)
def test_unifrac_matrix(self): """unifrac_matrix should return correct results for model tree""" m = array([[1,0,1],[1,1,0],[0,1,0],[0,0,1],[0,1,0],[0,1,1],[1,1,1],\ [0,1,1],[1,1,1]]) bl = self.branch_lengths result = unifrac_matrix(bl, m) self.assertEqual(result, array([[0, 10/16.,8/13.],[10/16.,0,8/17.],\ [8/13.,8/17.,0]])) #should work if we tell it the measure is asymmetric result = unifrac_matrix(bl, m, is_symmetric=False) self.assertEqual(result, array([[0, 10/16.,8/13.],[10/16.,0,8/17.],\ [8/13.,8/17.,0]])) #should work if the measure really is asymmetric result = unifrac_matrix(bl, m, metric=unnormalized_G, is_symmetric=False) self.assertEqual(result, array([[0, 1/17.,2/17.],[9/17.,0,6/17.],\ [6/17.,2/17.,0]])) #should also match web site calculations envs = self.count_array bound_indices = bind_to_array(self.nodes, envs) bool_descendants(bound_indices) result = unifrac_matrix(bl, envs) exp = array([[0, 0.6250, 0.6154], [0.6250, 0, \ 0.4706], [0.6154, 0.4707, 0]]) assert (abs(result - exp)).max() < 0.001
def test_weighted_unifrac_matrix(self): """weighted unifrac matrix should return correct results for model tree""" #should match web site calculations envs = self.count_array bound_indices = bind_to_array(self.nodes, envs) sum_descendants(bound_indices) bl = self.branch_lengths tip_indices = [n._leaf_index for n in self.t.tips()] result = weighted_unifrac_matrix(bl, envs, tip_indices) exp = array([[0, 9.1, 4.5], [9.1, 0, \ 6.4], [4.5, 6.4, 0]]) assert (abs(result - exp)).max() < 0.001 #should work with branch length corrections td = bl.copy()[:, newaxis] tip_bindings = bind_to_parent_array(self.t, td) tips = [n._leaf_index for n in self.t.tips()] tip_distances(td, tip_bindings, tips) result = weighted_unifrac_matrix(bl, envs, tip_indices, bl_correct=True, tip_distances=td) exp = array([[0, 9.1/11.5, 4.5/(10.5+1./3)], [9.1/11.5, 0, \ 6.4/(11+1./3)], [4.5/(10.5+1./3), 6.4/(11+1./3), 0]]) assert (abs(result - exp)).max() < 0.001
def test_delete_empty_parents(self): """delete_empty_parents should remove empty parents from bound indices""" id_to_node, node_first_last = index_tree(self.t) bound_indices = bind_to_array(node_first_last, self.count_array[:,0:1]) bool_descendants(bound_indices) self.assertEqual(len(bound_indices), 4) deleted = delete_empty_parents(bound_indices) self.assertEqual(len(deleted), 2) for d in deleted: self.assertEqual(d[0][0], 1)
def test_weighted_unifrac_vector(self): """weighted_unifrac_vector should ret correct results for model tree""" envs = self.count_array bound_indices = bind_to_array(self.nodes, envs) sum_descendants(bound_indices) bl = self.branch_lengths tip_indices = [n._leaf_index for n in self.t.tips()] result = weighted_unifrac_vector(bl, envs, tip_indices) self.assertFloatEqual( result[0], sum( [ abs(1.0 / 2 - 2.0 / 8) * 1, abs(1.0 / 2 - 1.0 / 8) * 2, abs(0 - 1.0 / 8) * 3, abs(0 - 3.0 / 8) * 1, abs(0 - 1.0 / 8) * 1, abs(0 - 4.0 / 8) * 2, abs(2.0 / 2 - 3.0 / 8) * 4, abs(0.0 - 5.0 / 8) * 3.0, ] ), ) self.assertFloatEqual( result[1], sum( [ abs(0 - 0.6) * 1, abs(0.2 - 0.2) * 2, abs(0.2 - 0) * 3, abs(0.6 - 0) * 1, abs(0 - 0.2) * 1, abs(0.6 - 0.2) * 2, abs(0.2 - 0.8) * 4, abs(0.8 - 0.2) * 3, ] ), ) self.assertFloatEqual( result[2], sum( [ abs(2.0 / 3 - 1.0 / 7) * 1, abs(0 - 2.0 / 7) * 2, abs(0 - 1.0 / 7) * 3, abs(0 - 3.0 / 7) * 1, abs(1.0 / 3 - 0) * 1, abs(1.0 / 3 - 3.0 / 7) * 2, abs(2.0 / 3 - 3.0 / 7) * 4, abs(1.0 / 3 - 4.0 / 7) * 3, ] ), )
def test_delete_empty_parents(self): """delete_empty_parents should remove empty parents from bound indices""" id_to_node, node_first_last = index_tree(self.t) bound_indices = bind_to_array(node_first_last, self.count_array[:, 0:1]) bool_descendants(bound_indices) self.assertEqual(len(bound_indices), 4) deleted = delete_empty_parents(bound_indices) self.assertEqual(len(deleted), 2) for d in deleted: self.assertEqual(d[0][0], 1)
def test_env_unique_fraction(self): """should report unique fraction of bl in each env """ # testing old unique fraction cur_count_array = self.count_array.copy() bound_indices = bind_to_array(self.nodes, cur_count_array) total_bl = sum(self.branch_lengths) bool_descendants(bound_indices) env_bl_sums, env_bl_ufracs = env_unique_fraction(self.branch_lengths, cur_count_array) # env A has 0 unique bl, B has 4, C has 1 self.assertEqual(env_bl_sums, [0,4,1]) self.assertEqual(env_bl_ufracs, [0,4/17.0,1/17.0]) cur_count_array = self.old_count_array.copy() bound_indices = bind_to_array(self.old_nodes, cur_count_array) total_bl = sum(self.old_branch_lengths) bool_descendants(bound_indices) env_bl_sums, env_bl_ufracs = env_unique_fraction(self.old_branch_lengths, cur_count_array) # env A has 0 unique bl, B has 4, C has 1 self.assertEqual(env_bl_sums, env_bl_sums) self.assertEqual(env_bl_sums, [1.29, 0.33999999999999997, 0.63]) self.assertEqual(env_bl_ufracs, [1.29/2.9,0.33999999999999997/2.9, 0.63/2.9])
def test_sum_descendants(self): """sum_descendants should sum total descendants w/ each state""" id_, child = index_tree(self.t3) a = zeros((11, 3)) + 99 #fill with junk bindings = bind_to_array(child, a) #load in leaf envs a[0] = a[1] = a[2] = a[7] = [0, 1, 0] a[3] = [1, 0, 0] a[6] = [0, 0, 1] sum_descendants(bindings) self.assertEqual(a, \ array([[0,1,0],[0,1,0],[0,1,0],[1,0,0],[0,3,0],[1,0,0],\ [0,0,1],[0,1,0],[1,3,0],[0,1,1],[1,4,1]]) )
def test_traverse_reduce(self): """traverse_reduce should reduce array in traversal order.""" id_, child = index_tree(self.t3) a = zeros((11, 3)) + 99 # fill with junk bindings = bind_to_array(child, a) # load in leaf envs a[0] = a[1] = a[2] = a[7] = [0, 1, 0] a[3] = [1, 0, 0] a[6] = [0, 0, 1] f = logical_or.reduce traverse_reduce(bindings, f) self.assertEqual( a, array( [ [0, 1, 0], [0, 1, 0], [0, 1, 0], [1, 0, 0], [0, 1, 0], [1, 0, 0], [0, 0, 1], [0, 1, 0], [1, 1, 0], [0, 1, 1], [1, 1, 1], ] ), ) f = sum traverse_reduce(bindings, f) self.assertEqual( a, array( [ [0, 1, 0], [0, 1, 0], [0, 1, 0], [1, 0, 0], [0, 3, 0], [1, 0, 0], [0, 0, 1], [0, 1, 0], [1, 3, 0], [0, 1, 1], [1, 4, 1], ] ), )
def test_fitch_descendants(self): """fitch_descendants should assign states by fitch parsimony, ret. #""" id_, child = index_tree(self.t3) a = zeros((11, 3)) + 99 #fill with junk bindings = bind_to_array(child, a) #load in leaf envs a[0] = a[1] = a[2] = a[7] = [0, 1, 0] a[3] = [1, 0, 0] a[6] = [0, 0, 1] changes = fitch_descendants(bindings) self.assertEqual(changes, 2) self.assertEqual(a, \ array([[0,1,0],[0,1,0],[0,1,0],[1,0,0],[0,1,0],[1,0,0],\ [0,0,1],[0,1,0],[1,1,0],[0,1,1],[0,1,0]]) )
def test_bool_descendants(self): """bool_descendants should be true if any descendant true""" #self.t3 = DndParser('(((a,b,c),(d)),(e,f))', UniFracTreeNode) id_, child = index_tree(self.t3) a = zeros((11, 3)) + 99 #fill with junk bindings = bind_to_array(child, a) #load in leaf envs a[0] = a[1] = a[2] = a[7] = [0, 1, 0] a[3] = [1, 0, 0] a[6] = [0, 0, 1] bool_descendants(bindings) self.assertEqual(a, \ array([[0,1,0],[0,1,0],[0,1,0],[1,0,0],[0,1,0],[1,0,0],\ [0,0,1],[0,1,0],[1,1,0],[0,1,1],[1,1,1]]) )
def test_weighted_unifrac_vector(self): """weighted_unifrac_vector should return correct results for model tree""" envs = self.count_array bound_indices = bind_to_array(self.nodes, envs) sum_descendants(bound_indices) bl = self.branch_lengths tip_indices = [n._leaf_index for n in self.t.tips()] result = weighted_unifrac_vector(bl, envs, tip_indices) self.assertFloatEqual( result[0], sum([ abs(1. / 2 - 2. / 8) * 1, abs(1. / 2 - 1. / 8) * 2, abs(0 - 1. / 8) * 3, abs(0 - 3. / 8) * 1, abs(0 - 1. / 8) * 1, abs(0 - 4. / 8) * 2, abs(2. / 2 - 3. / 8) * 4, abs(0. - 5. / 8) * 3. ])) self.assertFloatEqual( result[1], sum([ abs(0 - .6) * 1, abs(.2 - .2) * 2, abs(.2 - 0) * 3, abs(.6 - 0) * 1, abs(0 - .2) * 1, abs(.6 - .2) * 2, abs(.2 - .8) * 4, abs(.8 - .2) * 3 ])) self.assertFloatEqual( result[2], sum([ abs(2. / 3 - 1. / 7) * 1, abs(0 - 2. / 7) * 2, abs(0 - 1. / 7) * 3, abs(0 - 3. / 7) * 1, abs(1. / 3 - 0) * 1, abs(1. / 3 - 3. / 7) * 2, abs(2. / 3 - 3. / 7) * 4, abs(1. / 3 - 4. / 7) * 3 ]))
def test_unifrac_matrix(self): """unifrac_matrix should return correct results for model tree""" m = array([[1, 0, 1], [1, 1, 0], [0, 1, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 1, 1], [0, 1, 1], [1, 1, 1]]) bl = self.branch_lengths result = unifrac_matrix(bl, m) self.assertEqual(result, array([[0, 10 / 16.0, 8 / 13.0], [10 / 16.0, 0, 8 / 17.0], [8 / 13.0, 8 / 17.0, 0]])) # should work if we tell it the measure is asymmetric result = unifrac_matrix(bl, m, is_symmetric=False) self.assertEqual(result, array([[0, 10 / 16.0, 8 / 13.0], [10 / 16.0, 0, 8 / 17.0], [8 / 13.0, 8 / 17.0, 0]])) # should work if the measure really is asymmetric result = unifrac_matrix(bl, m, metric=unnormalized_G, is_symmetric=False) self.assertEqual(result, array([[0, 1 / 17.0, 2 / 17.0], [9 / 17.0, 0, 6 / 17.0], [6 / 17.0, 2 / 17.0, 0]])) # should also match web site calculations envs = self.count_array bound_indices = bind_to_array(self.nodes, envs) bool_descendants(bound_indices) result = unifrac_matrix(bl, envs) exp = array([[0, 0.6250, 0.6154], [0.6250, 0, 0.4706], [0.6154, 0.4707, 0]]) assert (abs(result - exp)).max() < 0.001
def test_bind_to_array(self): """bind_to_array should return correct array ranges""" a = reshape(arange(33), (11, 3)) id_, child = index_tree(self.t3) bindings = bind_to_array(child, a) self.assertEqual(len(bindings), 5) self.assertEqual(bindings[0][0], a[4]) self.assertEqual(bindings[0][1], a[0:3]) self.assertEqual(bindings[0][1].shape, (3, 3)) self.assertEqual(bindings[1][0], a[5]) self.assertEqual(bindings[1][1], a[3:4]) self.assertEqual(bindings[1][1].shape, (1, 3)) self.assertEqual(bindings[2][0], a[8]) self.assertEqual(bindings[2][1], a[4:6]) self.assertEqual(bindings[2][1].shape, (2, 3)) self.assertEqual(bindings[3][0], a[9]) self.assertEqual(bindings[3][1], a[6:8]) self.assertEqual(bindings[3][1].shape, (2, 3)) self.assertEqual(bindings[4][0], a[10]) self.assertEqual(bindings[4][1], a[8:10]) self.assertEqual(bindings[4][1].shape, (2, 3))
def test_traverse_reduce(self): """traverse_reduce should reduce array in traversal order.""" id_, child = index_tree(self.t3) a = zeros((11, 3)) + 99 #fill with junk bindings = bind_to_array(child, a) #load in leaf envs a[0] = a[1] = a[2] = a[7] = [0, 1, 0] a[3] = [1, 0, 0] a[6] = [0, 0, 1] f = logical_or.reduce traverse_reduce(bindings, f) self.assertEqual(a,\ array([[0,1,0],[0,1,0],[0,1,0],[1,0,0],[0,1,0],[1,0,0],\ [0,0,1],[0,1,0],[1,1,0],[0,1,1],[1,1,1]]) ) f = sum traverse_reduce(bindings, f) self.assertEqual( a, \ array([[0,1,0],[0,1,0],[0,1,0],[1,0,0],[0,3,0],[1,0,0],\ [0,0,1],[0,1,0],[1,3,0],[0,1,1],[1,4,1]]) )
def test_bind_to_array(self): """bind_to_array should return correct array ranges""" a = reshape(arange(33), (11,3)) id_, child = index_tree(self.t3) bindings = bind_to_array(child, a) self.assertEqual(len(bindings), 5) self.assertEqual(bindings[0][0], a[4]) self.assertEqual(bindings[0][1], a[0:3]) self.assertEqual(bindings[0][1].shape, (3,3)) self.assertEqual(bindings[1][0], a[5]) self.assertEqual(bindings[1][1], a[3:4]) self.assertEqual(bindings[1][1].shape, (1,3)) self.assertEqual(bindings[2][0], a[8]) self.assertEqual(bindings[2][1], a[4:6]) self.assertEqual(bindings[2][1].shape, (2,3)) self.assertEqual(bindings[3][0], a[9]) self.assertEqual(bindings[3][1], a[6:8]) self.assertEqual(bindings[3][1].shape, (2,3)) self.assertEqual(bindings[4][0], a[10]) self.assertEqual(bindings[4][1], a[8:10]) self.assertEqual(bindings[4][1].shape, (2,3))