For node with children , the phylogenetic pruning algorithm combines the two conditionally independent descendant subtrees:The likelihood function is under a uniform ancestral prior. In the supplied numbering, children have smaller indices than their parents, so increasing node order is a valid bottom-up traversal:
def felsenstein(prob, mu, L, left, right, left_time, right_time):
# All four entries are overwritten at every internal node.
for node in range(L, 2*L-1):
Tl = np.array([[jukes(a,b,left_time[node],mu)
for b in range(4)] for a in range(4)])
Tr = np.array([[jukes(a,b,right_time[node],mu)
for b in range(4)] for a in range(4)])
prob[node] = (Tl @ prob[left[node]]) * (Tr @ prob[right[node]])
return float(np.log(prob[-1].mean()))
print(felsenstein(prob, .5, len(leaves), left, right, left_time, right_time))At , the log-likelihood is . Internal rows must remain unnormalized in this implementation, because their magnitudes contribute to the tree likelihood function; normalization without retaining the removed factors would lose that information. The final root normalization required for a posterior probability is a separate step in part (e).
Articles by others on the same topic
There are currently no matching articles.