def test_isComplex(self): """Rates isComplex should return True if complex elements""" r = Rates([0,0,0.1j,0,0,0,0,0,0], self.abc_pairs) assert r.isComplex() r = Rates([0,0,0.1,0,0,0,0,0,0], self.abc_pairs) assert not r.isComplex()
def test_fixNegsConstrainedOpt(self): """Rates fixNegsConstrainedOpt should fix negatives w/ constrained opt""" q = Rates(array([[-0.28936029, 0.14543346, -0.02648614, 0.17041297], [ 0.00949624, -0.31186005, 0.17313171, 0.1292321 ], [ 0.10443209, 0.16134479, -0.30480186, 0.03902498], [ 0.01611264, 0.12999161, 0.15558259, -0.30168684]]), DnaPairs) r = q.fixNegsFmin() assert not q.isValid() assert r.isValid()
def test_fixNegsEven(self): """Rates fixNegsEven should fix negatives by adding evenly to others""" q = Rates( [[-6, 2, 2, 2], [-3, -2, 3, 2], [-2, -2, -6, 2], [4, 4, -6, -2]], RnaPairs) m = q.fixNegsEven()._data self.assertEqual( m, array([[-6, 2, 2, 2], [0, -3, 2, 1], [0, 0, -0, 0], [2, 2, 0, -4]]))
def test_normalize(self): """Rates normalize should return normalized copy of self where trace=-1""" r = Rates([-2, 1, 1, 0, -1, 1, 2, 0, -1], self.abc_pairs) n = r.normalize() self.assertEqual(n._data, \ array([[-0.5,.25,.25],[0.,-.25,.25],[.5,0.,-.25]])) #check that we didn't change the original assert n._data is not r._data self.assertEqual(r._data, \ array([[-2,1,1,],[0,-1,1,],[2,0,-1]]))
def test_normalize(self): """Rates normalize should return normalized copy of self where trace=-1""" r = Rates([-2,1,1,0,-1,1,2,0,-1], self.abc_pairs) n = r.normalize() self.assertEqual(n._data, \ array([[-0.5,.25,.25],[0.,-.25,.25],[.5,0.,-.25]])) #check that we didn't change the original assert n._data is not r._data self.assertEqual(r._data, \ array([[-2,1,1,],[0,-1,1,],[2,0,-1]]))
def test_fixNegsDiag(self): """Rates fixNegsDiag should fix negatives by adding to diagonal""" q = Rates( [[-6, 2, 2, 2], [-6, -2, 4, 4], [2, 2, -6, 2], [4, 4, -2, -6]], RnaPairs) m = q.fixNegsDiag()._data self.assertEqual( m, array([[-6, 2, 2, 2], [0, -8, 4, 4], [2, 2, -6, 2], [4, 4, 0, -8]]))
def test_fixNegsConstrainedOpt(self): """Rates fixNegsConstrainedOpt should fix negatives w/ constrained opt""" q = Rates( array([[-0.28936029, 0.14543346, -0.02648614, 0.17041297], [0.00949624, -0.31186005, 0.17313171, 0.1292321], [0.10443209, 0.16134479, -0.30480186, 0.03902498], [0.01611264, 0.12999161, 0.15558259, -0.30168684]]), DnaPairs) r = q.fixNegsFmin() assert not q.isValid() assert r.isValid()
def test_isSignificantlyComplex(self): """Rates isSignificantlyComplex should be true if large imag component""" r = Rates([0, 0, 0.2j, 0, 0, 0, 0, 0, 0], self.abc_pairs) assert r.isSignificantlyComplex() assert r.isSignificantlyComplex(0.01) assert not r.isSignificantlyComplex(0.2) assert not r.isSignificantlyComplex(0.3) r = Rates([0, 0, 0.1, 0, 0, 0, 0, 0, 0], self.abc_pairs) assert not r.isSignificantlyComplex() assert not r.isSignificantlyComplex(1e-30) assert not r.isSignificantlyComplex(1e3)
def test_init(self): """Rates init should take additional parameter to normalize""" r = Rates([-2, 1, 1, 0, -1, 1, 0, 0, 0], self.abc_pairs) self.assertEqual(r._data, array([[-2, 1, 1], [0, -1, 1], [0, 0, 0]])) r = Rates([-2.5, 1, 1, 0, -1, 1, 0, 0, 0], self.abc_pairs) self.assertEqual(r._data, array([[-2.5, 1., 1.], [0., -1., 1.], [0., 0., 0.]])) r = Rates([-2, 1, 1, 0, -1, 1, 2, 0, -1], self.abc_pairs, normalize=True) self.assertEqual(r._data, \ array([[-0.5,.25,.25],[0.,-.25,.25],[.5,0.,-.25]]))
def test_toSimilarProbs(self): """Rates toSimilarProbs should match individual steps""" a = self.abc_pairs p = Probs([0.75, 0.1, 0.15, 0.2, 0.7, 0.1, 0.05, 0.15, 0.8], a) q = p.toRates() self.assertEqual(q.toSimilarProbs(0.5), \ q.toProbs(q.timeForSimilarity(0.5))) #test a case that didn't work for DNA q = Rates(array( [[-0.64098451, 0.0217681 , 0.35576469, 0.26345171], [ 0.31144238, -0.90915091, 0.25825858, 0.33944995], [ 0.01578521, 0.43162879, -0.99257581, 0.54516182], [ 0.13229986, 0.04027147, 0.05817791, -0.23074925]]), DnaPairs) p = q.toSimilarProbs(0.66) self.assertFloatEqual(average(diagonal(p._data), axis=0), 0.66)
def test_toProbs(self): """Rates toProbs should return correct probability matrix""" a = self.abc_pairs p = Probs([0.75, 0.1, 0.15, 0.2, 0.7, 0.1, 0.05, 0.1, 0.85], a) q = p.toRates() self.assertEqual(q._data, logm(p._data)) p2 = q.toProbs() self.assertFloatEqual(p2._data, p._data) #test a case that didn't work for DNA q = Rates(array( [[-0.64098451, 0.0217681 , 0.35576469, 0.26345171], [ 0.31144238, -0.90915091, 0.25825858, 0.33944995], [ 0.01578521, 0.43162879, -0.99257581, 0.54516182], [ 0.13229986, 0.04027147, 0.05817791, -0.23074925]]), DnaPairs) self.assertFloatEqual(q.toProbs(0.5)._data, expm(q._data)(t=0.5))
def test_random_q_matrix_diag_vector(self): """Rates random should init with vector as diagonal""" diag = [1, -1, 2, -2] for i in range(NUM_TESTS): q = Rates.random(RnaPairs, diag)._data for i, d, row in zip(range(4), diag, q): self.assertFloatEqual(sum(row, axis=0), 0.0) self.assertEqual(row[i], diag[i])
def test_toProbs(self): """Rates toProbs should return correct probability matrix""" a = self.abc_pairs p = Probs([0.75, 0.1, 0.15, 0.2, 0.7, 0.1, 0.05, 0.1, 0.85], a) q = p.toRates() self.assertEqual(q._data, logm(p._data)) p2 = q.toProbs() self.assertFloatEqual(p2._data, p._data) #test a case that didn't work for DNA q = Rates( array([[-0.64098451, 0.0217681, 0.35576469, 0.26345171], [0.31144238, -0.90915091, 0.25825858, 0.33944995], [0.01578521, 0.43162879, -0.99257581, 0.54516182], [0.13229986, 0.04027147, 0.05817791, -0.23074925]]), DnaPairs) self.assertFloatEqual(q.toProbs(0.5)._data, expm(q._data)(t=0.5))
def test_toSimilarProbs(self): """Rates toSimilarProbs should match individual steps""" a = self.abc_pairs p = Probs([0.75, 0.1, 0.15, 0.2, 0.7, 0.1, 0.05, 0.15, 0.8], a) q = p.toRates() self.assertEqual(q.toSimilarProbs(0.5), \ q.toProbs(q.timeForSimilarity(0.5))) #test a case that didn't work for DNA q = Rates( array([[-0.64098451, 0.0217681, 0.35576469, 0.26345171], [0.31144238, -0.90915091, 0.25825858, 0.33944995], [0.01578521, 0.43162879, -0.99257581, 0.54516182], [0.13229986, 0.04027147, 0.05817791, -0.23074925]]), DnaPairs) p = q.toSimilarProbs(0.66) self.assertFloatEqual(average(diagonal(p._data), axis=0), 0.66)
def test_isSignificantlyComplex(self): """Rates isSignificantlyComplex should be true if large imag component""" r = Rates([0,0,0.2j,0,0,0,0,0,0], self.abc_pairs) assert r.isSignificantlyComplex() assert r.isSignificantlyComplex(0.01) assert not r.isSignificantlyComplex(0.2) assert not r.isSignificantlyComplex(0.3) r = Rates([0,0,0.1,0,0,0,0,0,0], self.abc_pairs) assert not r.isSignificantlyComplex() assert not r.isSignificantlyComplex(1e-30) assert not r.isSignificantlyComplex(1e3)
def test_isValid(self): """Rates isValid should check row sums and neg off-diags""" r = Rates([-2,1,1,0,-1,1,0,0,0], self.abc_pairs) assert r.isValid() r = Rates([0,0,0,0,0,0,0,0,0], self.abc_pairs) assert r.isValid() #not valid if negative off-diagonal r = Rates([-2,-1,3,1,-1,0,2,2,-4], self.abc_pairs) assert not r.isValid() #not valid if rows don't all sum to 0 r = Rates([0,0.0001,0,0,0,0,0,0,0], self.abc_pairs) assert not r.isValid()
def test_evolve(self): """RangeNode evolve should work on a starting vector""" t = self.t1 t.Q = Rates.random(DnaPairs) t.assignQ() t.assignLength(0.1) t.assignP() start = array([1,0,2,1,0,0,2,1,2,0,1,2,1,0,2,0,0,3,0,2,1,0,3,1,0,2,0,0,0,0,0,1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,3]) t.evolve(start) for i in t.traverse(): self.assertEqual(len(i.Sequence), len(start)) self.assertNotEqual(i.Sequence, start)
def test_isComplex(self): """Rates isComplex should return True if complex elements""" r = Rates([0, 0, 0.1j, 0, 0, 0, 0, 0, 0], self.abc_pairs) assert r.isComplex() r = Rates([0, 0, 0.1, 0, 0, 0, 0, 0, 0], self.abc_pairs) assert not r.isComplex()
def test_assignP(self): """RangeNode assignP should work when Qs set.""" t = self.t1 for i in t.traverse(self_before=True): i.Length = random() * 0.5 #range 0 to 0.5 t.Q = Rates.random(DnaPairs) t.assignQ() t.assignP() t.assignIds() for node in t.traverse(self_after=True): if node.Parent is not None: self.assertFloatEqual(average(1-diag(node.P._data), axis=0), \ node.Length)
def test_random_q_matrix(self): """Rates random should return matrix of correct size""" for i in range(NUM_TESTS): q = Rates.random(RnaPairs)._data self.assertEqual(len(q), 4) self.assertEqual(len(q[0]), 4) for row in q: self.assertFloatEqual(sum(row), 0.0) assert min(row) < 0 assert max(row) > 0 l = list(row) l.sort() assert min(l[1:]) >= 0 assert max(l[1:]) <= 1
def test_random_q_matrix_diag(self): """Rates random should set diagonal correctly from scalar""" for i in range(NUM_TESTS): q = Rates.random(RnaPairs, -1)._data self.assertEqual(len(q), 4) for i, row in enumerate(q): self.assertFloatEqual(sum(row), 0) self.assertEqual(row[i], -1) assert max(row) <= 1 l = list(row) l.sort() assert min(l[1:]) >= 0 assert max(l[1:]) <= 1 for i in range(NUM_TESTS): q = Rates.random(RnaPairs, -5)._data self.assertEqual(len(q), 4) for i, row in enumerate(q): self.assertFloatEqual(sum(row), 0) self.assertEqual(row[i], -5) assert max(row) <= 5 l = list(row) l.sort() assert min(l[1:]) >= 0 assert max(l[1:]) <= 5
def test_tree_twoway_rates(self): """tree_twoway_rates should give plausible results on rand trees""" t = self.t1 t.assignLength(0.05) t.Q = Rates.random(DnaPairs).normalize() t.assignQ() t.assignP() t.evolve(randint(0,4,100)) t.makeIdIndex() result = tree_twoway_rates(t) self.assertEqual(result.shape, (5,5,16)) #check that row sums are 0 for x in [(i,j) for i in range(5) for j in range(5)]: self.assertFloatEqual(sum(result[x]), 0) #need to make sure we didn't just get an empty array self.assertGreaterThan((abs(result)).sum(), 0) #check that it works without_diag result = tree_twoway_rates(t, without_diag=True) self.assertEqual(result.shape, (5,5,12)) #check that it works with/without normalize #default: no normalization, so row sums shouldn't be 1 after omitting #diagonal result = tree_twoway_rates(t, without_diag=True) self.assertEqual(result.shape, (5,5,12)) #check that the row sums are not 1 before normalization (note that they #can be zero, though) sums_before = [] for x in [(i,j) for i in range(5) for j in range(5)]: curr_sum = sum(result[x]) sums_before.append(curr_sum) #...but if we tell it to normalize, row sums should be nearly 1 #after omitting diagonal result = tree_twoway_rates(t, without_diag=True, \ normalize=True) self.assertEqual(result.shape, (5,5,12)) sums_after = [] for x in [(i,j) for i in range(5) for j in range(5)]: curr_sum = sum(result[x]) sums_after.append(curr_sum) if curr_sum != 0: self.assertFloatEqual(curr_sum, 1) try: self.assertFloatEqual(sums_before, sums_after) except AssertionError: pass else: raise AssertionError, "Expected different arrays before/after norm"
def test_tree_threeway_rates(self): """tree_threeway_rates should give plausible results on rand trees""" #note: the following fails occasionally, but repeating it 5 times #and checking that one passes is fairly safe for i in range(5): try: t = self.t1 t.assignLength(0.05) t.Q = Rates.random(DnaPairs).normalize() t.assignQ() t.assignP() t.evolve(randint(0,4,100)) t.makeIdIndex() depths = t.leafLcaDepths() result = tree_threeway_rates(t, depths) self.assertEqual(result.shape, (5,5,5,16)) #check that row sums are 0 for x in [(i,j,k) for i in range(5) for j in range(5) \ for k in range(5)]: self.assertFloatEqual(sum(result[x]), 0) assert any(result) #check that it works without_diag result = tree_threeway_rates(t, depths, without_diag=True) self.assertEqual(result.shape, (5,5,5,12)) #check that it works with/without normalize #default: no normalization, so row sums shouldn't be 1 after #omitting diagonal result = tree_threeway_rates(t, depths, without_diag=True) self.assertEqual(result.shape, (5,5,5,12)) for x in [(i,j,k) for i in range(5) for j in range(5) \ for k in range(5)]: assert sum(result[x]) == 0 or abs(sum(result[x]) - 1) > 0.01 #...but if we tell it to normalize, row sums should be nearly 1 #after omitting diagonal result = tree_threeway_rates(t, depths, without_diag=True, \ normalize=True) self.assertEqual(result.shape, (5,5,5,12)) for x in [(i,j,k) for i in range(5) for j in range(5) \ for k in range(5)]: s = sum(result[x]) if s != 0: self.assertFloatEqual(s, 1) break except AssertionError: pass
def test_assignPs(self): """RangeNode assignPs should assign multiple scaled P matrices""" t = self.t1 for i in t.traverse(self_before=True): i.Length = random() * 0.5 #range 0 to 0.5 t.Q = Rates.random(DnaPairs) t.assignQ() t.assignPs([1, 0.5, 0.25]) t.assignIds() for node in t.traverse(self_after=True): if node.Parent is not None: self.assertEqual(len(node.Ps), 3) self.assertFloatEqual(average(1-diag(node.Ps[0]._data), axis=0), \ node.Length) self.assertFloatEqual(average(1-diag(node.Ps[1]._data), axis=0), \ 0.5*node.Length) self.assertFloatEqual(average(1-diag(node.Ps[2]._data), axis=0), \ 0.25*node.Length)
def test_rates_to_array(self): """rates_to_array should pack rates into array correctly""" m1 = array([[-1, 1, 1, 1], [2, -2, 2, 2], [3, 3, -3, 3], [1, 2, 3, -4]]) m2 = m1 * 2 m3 = m1 * 0.5 m4 = zeros((4, 4)) m5 = array([0, 0]) r1, r2, r3, r4, r5 = [Rates(i, DnaPairs) for i in m1, m2, m3, m4, m5] data = {(0, 1, 0): r1, (1, 2, 0): r2, (2, 0, 0): r3, (2, 1, 1): r4} #note that array can be, but need not be, floating point to_fill = zeros((3, 3, 3, 16), 'float64') result = rates_to_array(data, to_fill) #check that the thnigs we deliberately set are OK self.assertEqual(to_fill[0][1][0], ravel(m1)) self.assertNotEqual(to_fill[0][1][0], ravel(m2)) self.assertEqual(to_fill[1, 2, 0], ravel(m2)) self.assertEqual(to_fill[2][0][0], ravel(m3)) self.assertEqual(to_fill[2][1][1], ravel(m4)) #check that everything else is zero nonzero = [(0, 1, 0), (1, 2, 0), (2, 0, 0)] for x in [(i, j, k) for i in range(3) for j in range(3) \ for k in range(3)]: if x not in nonzero: self.assertEqual(to_fill[x], zeros(16)) #check that it works omitting the diagonal to_fill = zeros((3, 3, 3, 12), 'float64') result = rates_to_array(data, to_fill, without_diagonal=True) #check that the thnigs we deliberately set are OK m1_nodiag = array([[1, 1, 1], [2, 2, 2], [3, 3, 3], [1, 2, 3]]) self.assertEqual(to_fill[0][1][0], ravel(m1_nodiag)) self.assertNotEqual(to_fill[0][1][0], ravel(m1_nodiag * 2)) self.assertEqual(to_fill[1, 2, 0], ravel(m1_nodiag * 2)) self.assertEqual(to_fill[2][0][0], ravel(m1_nodiag * 0.5)) self.assertEqual(to_fill[2][1][1], zeros(12)) #check that everything else is zero nonzero = [(0, 1, 0), (1, 2, 0), (2, 0, 0)] for x in [(i, j, k) for i in range(3) for j in range(3) \ for k in range(3)]: if x not in nonzero: self.assertEqual(to_fill[x], zeros(12))
def test_evolveSeqs(self): """PhlyoNode evolveSeqs should evolve multiple sequences""" t = self.t1 for i in t.traverse(self_before=True): i.Length = 0.5 t.Q = Rates.random(DnaPairs) t.assignQ() t.assignPs([1, 1, 0.1]) t.assignIds() orig_seqs = [array(i) for i in [randint(0,4,200), randint(0,4,200), \ randint(0,4,200)]] t.evolveSeqs(orig_seqs) for node in t.traverse(): #only look at leaves if node.Parent is not None: self.assertEqual(len(node.Sequences), 3) for orig, new in zip(orig_seqs, node.Sequences): self.assertEqual(len(orig), len(new)) self.assertNotEqual(orig, new) assert sum(orig_seqs[1]!=node.Sequences[1]) > \ sum(orig_seqs[2]!=node.Sequences[2])
def test_fixNegsReflect(self): """Rates fixNegsReflect should reflect negatives across diagonal""" ab = Alphabet('ab')**2 #should leave matrix alone if no off-diagonal elements q = Rates([0,0,1,-1], ab) self.assertEqual(q.fixNegsReflect()._data, array([[0,0],[1,-1]])) q = Rates([-2,2,1,-1], ab) self.assertEqual(q.fixNegsReflect()._data, array([[-2,2],[1,-1]])) #should work if precisely one off-diag element in a pair is negative q = Rates([2,-2,1,-1], ab) self.assertEqual(q.fixNegsReflect()._data, array([[0,0],[3,-3]])) q = Rates([-1,1,-2,2], ab) self.assertEqual(q.fixNegsReflect()._data, array([[-3,3],[0,-0]])) #should work if both off-diag elements in a pair are negative q = Rates([1,-1,-2,2], ab) self.assertEqual(q.fixNegsReflect()._data, array([[-2,2],[1,-1]])) q = Rates([2,-2,-1,1], ab) self.assertEqual(q.fixNegsReflect()._data, array([[-1,1],[2,-2]])) q = Rates([[ 0, 3, -2, -1], [ 2, -1, 2, -3], [-1, -1, 2, 0], [-3, 2, 0, 1]], RnaPairs) q2 = q.fixNegsReflect() self.assertEqual(q2._data, \ array([[-7, 3, 1, 3], [ 2, -5, 3, 0], [ 2, 0, -2, 0], [ 1, 5, 0, -6]]))
def test_isValid(self): """Rates isValid should check row sums and neg off-diags""" r = Rates([-2, 1, 1, 0, -1, 1, 0, 0, 0], self.abc_pairs) assert r.isValid() r = Rates([0, 0, 0, 0, 0, 0, 0, 0, 0], self.abc_pairs) assert r.isValid() #not valid if negative off-diagonal r = Rates([-2, -1, 3, 1, -1, 0, 2, 2, -4], self.abc_pairs) assert not r.isValid() #not valid if rows don't all sum to 0 r = Rates([0, 0.0001, 0, 0, 0, 0, 0, 0, 0], self.abc_pairs) assert not r.isValid()
def test_fixNegsEven(self): """Rates fixNegsEven should fix negatives by adding evenly to others""" q = Rates([[-6,2,2,2],[-3,-2,3,2],[-2,-2,-6,2],[4,4,-6,-2]], RnaPairs) m = q.fixNegsEven()._data self.assertEqual(m,array([[-6,2,2,2],[0,-3,2,1],[0,0,-0,0],[2,2,0,-4]]))
def test_fixNegsDiag(self): """Rates fixNegsDiag should fix negatives by adding to diagonal""" q = Rates([[-6,2,2,2],[-6,-2,4,4],[2,2,-6,2],[4,4,-2,-6]], RnaPairs) m = q.fixNegsDiag()._data self.assertEqual(m,array([[-6,2,2,2],[0,-8,4,4],[2,2,-6,2],[4,4,0,-8]]))
def test_fixNegsReflect(self): """Rates fixNegsReflect should reflect negatives across diagonal""" ab = Alphabet('ab')**2 #should leave matrix alone if no off-diagonal elements q = Rates([0, 0, 1, -1], ab) self.assertEqual(q.fixNegsReflect()._data, array([[0, 0], [1, -1]])) q = Rates([-2, 2, 1, -1], ab) self.assertEqual(q.fixNegsReflect()._data, array([[-2, 2], [1, -1]])) #should work if precisely one off-diag element in a pair is negative q = Rates([2, -2, 1, -1], ab) self.assertEqual(q.fixNegsReflect()._data, array([[0, 0], [3, -3]])) q = Rates([-1, 1, -2, 2], ab) self.assertEqual(q.fixNegsReflect()._data, array([[-3, 3], [0, -0]])) #should work if both off-diag elements in a pair are negative q = Rates([1, -1, -2, 2], ab) self.assertEqual(q.fixNegsReflect()._data, array([[-2, 2], [1, -1]])) q = Rates([2, -2, -1, 1], ab) self.assertEqual(q.fixNegsReflect()._data, array([[-1, 1], [2, -2]])) q = Rates( [[0, 3, -2, -1], [2, -1, 2, -3], [-1, -1, 2, 0], [-3, 2, 0, 1]], RnaPairs) q2 = q.fixNegsReflect() self.assertEqual(q2._data, \ array([[-7, 3, 1, 3], [ 2, -5, 3, 0], [ 2, 0, -2, 0], [ 1, 5, 0, -6]]))