TEST_F(HullTest, IntegrateHullSegments) { // covers methods integrateSegment and normalizeHull double integral, integral1; double result; integral = (exp(h_x0 - hull.upper_hull_max - x0 * hp_x0) / hp_x0) * (exp(hp_x0 * z0) - exp(0.0)); integral = log(integral); result = hull.integrateSegment(hull.hull[0], 0.0); EXPECT_DOUBLE_EQ(integral, result); EXPECT_DOUBLE_EQ(integral, hull.hull[0].raw_integral); EXPECT_DOUBLE_EQ(integral, hull.hull[0].raw_cumulative_integral); integral1 = (exp(h_x1 - hull.upper_hull_max - x1 * hp_x1) / fabs(hp_x1)) * (exp(hp_x1 * z0)); integral1 = log(integral1); result = hull.integrateSegment(hull.hull[1], hull.hull[0].z); EXPECT_DOUBLE_EQ(integral1, result); EXPECT_DOUBLE_EQ(integral1, hull.hull[1].raw_integral); EXPECT_DOUBLE_EQ(logspaceAdd(integral, integral1), hull.hull[1].raw_cumulative_integral); EXPECT_EQ(0.0, hull.hull[1].cum_prob); EXPECT_EQ(integral - logspaceAdd(integral, integral1), hull.hull[0].cum_prob); double gamma_args[] = {2.0, 2.0}; hull.initialize(.25, 3.0, gamma_args); h_x0 = hull.hull[0].h_x; x0 = .25; z0 = hull.hull[0].z; hp_x0 = hull.hull[0].hprime_x; EXPECT_GT(hp_x0, 0.0); integral = (exp(h_x0 - hull.upper_hull_max - x0 * hp_x0) / hp_x0) * (exp(hp_x0 * z0) - exp(0.0)); result = hull.integrateSegment(hull.hull[0], 0.0); EXPECT_DOUBLE_EQ(log(integral), result); }
double logspaceAdd(const double loga, const double logb) { if (!R_FINITE(loga)) return logb; if (loga > logb) return logspaceAdd(logb, loga); return logb + log1p(exp(loga - logb)); }
/* Primary function for computing the gains/losses of a trait over * an entire phylogeny. * INPUTS: * tree: a PhyTree object * n_max: max n for which to compute probability * rate_0_to_1, rate_1_to_0: rates of transition between states * root_node_prob_0: probability root node is in state 0 * dist_type: either "prior" or "posterior" is computed * gains: if true, gains (0->1) distribution is computed, else losses (1->0) * distribution is computed * * OUTPUTS: * arma::mat of dimension (n_max + 1, 1), whose k-th element * is the (prior/posterior) probability of k (gains/losses) over * the given phylogeny at the given rates and root distribution. */ arma::mat convolveTree(const PhyTree & tree, const int & n_max, const double & rate_0_to_1, const double & rate_1_to_0, const double & root_node_prob_0, const std::string & dist_type, const bool gains) { PhyConvolver conv(n_max, tree.getNumNodes(), gains); conv.initializeTransdist(tree, dist_type); conv.fillQProbs(tree, rate_0_to_1, rate_1_to_0); for(int i = 0; i < tree.getNumEdges(); i += 2) { conv.fillNodeProbs(i, tree); } // root node is now a rescaled probability const int root_node_idx = tree.getNumTips(); IntegerVector tip_states_copy(tree.getNumTips()); for(int i = 0; i < tree.getNumTips(); i++) { tip_states_copy[i] = tree.getTipState(i); } arma::vec arma_root_dist(2); arma_root_dist(0) = root_node_prob_0; arma_root_dist(1) = 1.0 - root_node_prob_0; // get likelihood of tip data if we are computing posterior if (dist_type == "posterior") { const double post_lik = TwoStatePhyloLikelihood(tree.getEdgeMatrix() + 1, tip_states_copy, tree.getBranchLengths(), rate_0_to_1, rate_1_to_0, arma_root_dist); conv.rescale -= log(post_lik); } // gather root node vectors arma::mat root_dists = conv.getRootDists(root_node_idx); // transform output to log scale, rescale, and combine root_dists.transform(ip_log()); root_dists.col(0) += conv.rescale + log(root_node_prob_0); root_dists.col(1) += conv.rescale + log(1.0 - root_node_prob_0); arma::vec output(n_max + 1); for(int i = 0; i < output.n_rows; i++){ output(i) = logspaceAdd(root_dists(i, 0), root_dists(i, 1)); } return output; }