void slice_sample_branch_length(owned_ptr<Probability_Model>& P,MoveStats& Stats,int b) { Parameters& PP = *P.as<Parameters>(); PP.select_root(b); const double L = PP.T->directed_branch(b).length(); const double mu = PP.branch_mean(); MCMC::Result result(3); //------------- Find new length --------------// double sigma = loadvalue(P->keys,"slice_branch_sigma",1.5); // NOTE - it is OK to depend on L below -- IF AND ONLY IF the likelihood is unimodal. double w = sigma*(PP.branch_mean()+L); branch_length_slice_function logp(PP,b); double L2 = slice_sample(L,logp,w,100); //---------- Record Statistics - -------------// result.totals[0] = std::abs(L2 - L); result.totals[1] = std::abs(log(L2/L)); result.totals[2] = logp.count; Stats.inc("branch-length (slice) *",result); if (L < mu/2.0) Stats.inc("branch-length (slice) 1",result); else if (L < mu) Stats.inc("branch-length (slice) 2",result); else if (L < mu*2) Stats.inc("branch-length (slice) 3",result); else Stats.inc("branch-length (slice) 4",result); }
void slide_node(owned_ptr<Probability_Model>& P, MoveStats& Stats,int b0) { Parameters* PP = P.as<Parameters>(); vector<const_branchview> b; b.push_back( PP->T->directed_branch(b0) ); // choose branches to alter if (uniform() < 0.5) b[0] = b[0].reverse(); if (b[0].target().is_leaf_node()) b[0] = b[0].reverse(); append(b[0].branches_after(),b); b0 = b[0].name(); int b1 = b[1].undirected_name(); int b2 = b[2].undirected_name(); double L1a = PP->T->branch(b1).length(); double L2a = PP->T->branch(b2).length(); PP->set_root(b[0].target()); double p = loadvalue(P->keys,"branch_slice_fraction",0.9); if (uniform() < p) { slide_node_slice_function logp(*PP,b0); double w = logp.total * loadvalue(P->keys,"slide_branch_slice_window",0.3); double L1b = slice_sample(logp,w,100); MCMC::Result result(2); result.totals[0] = 2.0*std::abs(L1b-L1a); result.totals[1] = logp.count; Stats.inc("slide_node_slice",result); } else { bool success; string name; if (uniform() < 0.5) { success = slide_node(P, b, slide_node_no_expand_branch); name = "slide_node"; } else { success = slide_node(P, b, slide_node_expand_branch); name = "slide_node_expand_branch"; } PP = P.as<Parameters>(); double L1b = PP->T->branch(b1).length(); double L2b = PP->T->branch(b2).length(); MCMC::Result result(2); result.totals[0] = success?1:0; result.totals[1] = std::abs(L1b-L1a) + std::abs(L2b-L2a); Stats.inc(name,result); } }
void SPR_inc(MoveStats& Stats, MCMC::Result result,const string& name,double L) { Stats.inc(name, result); if (L < 0.5) Stats.inc(name+"-0.5", result); else if (L < 1) Stats.inc(name+"-1.0", result); else if (L < 2.0) Stats.inc(name+"-2.0", result); else Stats.inc(name+"-2.0+", result); }
void sample_tri_branch_one(Parameters& P, MoveStats& Stats,int b) { if (not P.smodel_full_tree and b>=P.T->n_leaves()) return; MCMC::Result result(2); assert(P.n_imodels() > 0); const SequenceTree& T = *P.T; int node1 = T.branch(b).target(); int node2 = T.branch(b).source(); if (myrandomf() < 0.5) std::swap(node1,node2); if (node1 < T.n_leaves()) std::swap(node1,node2); const double sigma = 0.3/2; double length1 = T.branch(b).length(); double length2 = length1 + gaussian(0,sigma); if (length2 < 0) length2 = -length2; if (tri_sample_alignment_branch(P,node1,node2,b,1,length2)) { result.totals[0] = 1; result.totals[1] = std::abs(length2 - length1); } Stats.inc("sample_tri_branch",result); }
void sample_tri_branch_type_one(Parameters& P, MoveStats& Stats,int b) { if (not P.smodel_full_tree and b>=P.T->n_leaves()) return; MCMC::Result result(1); assert(P.n_imodels() > 0); const SequenceTree& T = *P.T; int node1 = T.branch(b).target(); int node2 = T.branch(b).source(); if (myrandomf() < 0.5) std::swap(node1,node2); if (node1 < T.n_leaves()) std::swap(node1,node2); if (tri_sample_alignment_branch_model(P,node1,node2)) { result.totals[0] = 1; } Stats.inc("sample_tri_branch_type",result); }
void change_branch_length_flat(owned_ptr<Probability_Model>& P, MoveStats& Stats,int b,double sigma) { Parameters& PP = *P.as<Parameters>(); const double L = PP.T->directed_branch(b).length(); const double mu = PP.branch_mean(); MCMC::Result result = change_branch_length_(P, b, sigma*PP.branch_mean(), branch_twiddle_positive); Stats.inc("branch-length *",result); if (L < mu/2.0) Stats.inc("branch-length 1",result); else if (L < mu) Stats.inc("branch-length 2",result); else if (L < mu*2) Stats.inc("branch-length 3",result); else Stats.inc("branch-length 4",result); }
void change_branch_length_log_scale(owned_ptr<Probability_Model>& P, MoveStats& Stats, int b, double sigma) { const double L = P.as<Parameters>()->T->directed_branch(b).length(); const double mu = P.as<Parameters>()->branch_mean(); MCMC::Result result = change_branch_length_(P, b, sigma, scale_gaussian ); Stats.inc("branch-length (log) *",result); if (L < mu/2.0) Stats.inc("branch-length (log) 1",result); else if (L < mu) Stats.inc("branch-length (log) 2",result); else if (L < mu*2) Stats.inc("branch-length (log) 3",result); else Stats.inc("branch-length (log) 4",result); }
void sample_SPR_nodes(Parameters& P,MoveStats& Stats) { double f = loadvalue(P.keys,"SPR_amount",0.1); int n = poisson(P.T->n_branches()*f); double p = loadvalue(P.keys,"SPR_slice_fraction",-0.25); for(int i=0; i<n; i++) { int b1=-1, b2=-1; choose_subtree_branch_nodes(*P.T, b1, b2); if (P.n_imodels() == 0 and uniform()< p) { MCMC::Result result = sample_SPR(P,b1,b2,true); Stats.inc("SPR (path/slice)", result); } else { MCMC::Result result = sample_SPR(P,b1,b2); Stats.inc("SPR (path)", result); } } }
void Parameter_Slice_Move::iterate(owned_ptr<Model>& P,MoveStats& Stats,int) { double v1 = P->get_parameter_value(index).as_double(); parameter_slice_function logp(*P,index,transform,inverse); double v2 = sample(*P,logp,v1); //---------- Record Statistics - -------------// Result result(2); result.totals[0] = std::abs(v2-v1); result.totals[1] = logp.count; Stats.inc(name,result); }
/// Update statistics counters for an NNI move. void NNI_inc(MoveStats& Stats, const string& name, MCMC::Result result,double L) { Stats.inc(name, result); if (L < 0.0325) Stats.inc(name+"-0.0325", result); else if (L < 0.065) Stats.inc(name+"-0.065", result); else if (L < 0.125) Stats.inc(name+"-0.125", result); else if (L < 0.25) Stats.inc(name+"-0.25", result); else if (L < 0.5) Stats.inc(name+"-0.5", result); else if (L < 1) Stats.inc(name+"-1.0", result); else if (L < 2.0) Stats.inc(name+"-2.0", result); else Stats.inc(name+"-2.0+", result); }
void Modifiable_Slice_Move::iterate(owned_ptr<Model>& P,MoveStats& Stats,int) { #ifndef NDEBUG clog<<" [modifiable slice] move = "<<m_index<<endl; #endif double v1 = P->get_modifiable_value(m_index).as_double(); modifiable_slice_function logp(*P, m_index, bounds, transform, inverse); double v2 = sample(*P,logp,v1); //---------- Record Statistics --------------// Result result(2); result.totals[0] = std::abs(v2-v1); result.totals[1] = logp.count; Stats.inc(name,result); }
void Dirichlet_Modifiable_Slice_Move::iterate(owned_ptr<Model>& P,MoveStats& Stats,int) { #ifndef NDEBUG clog<<" [dirichlet modifiable slice] move"<<endl; #endif double v1 = P->get_modifiable_value(indices[n]).as_double(); constant_sum_modifiable_slice_function slice_levels_function(*P,indices,n); double v2 = sample(*P,slice_levels_function,v1); //---------- Record Statistics - -------------// Result result(2); vector<double> x = vec_to_double(P->get_modifiable_values(indices)); double total = sum(x); double factor = (total - v2)/(total-v1); result.totals[0] = std::abs(log(v2/v1)) + (indices.size()-1)*(std::abs(log(factor))); result.totals[1] = slice_levels_function.count; Stats.inc(name,result); }
void Scale_Means_Only_Slice_Move::iterate(owned_ptr<Model>& P, MoveStats& Stats,int) { #ifndef NDEBUG clog<<" [scale means only slice] move"<<endl; #endif Parameters& PP = *P.as<Parameters>(); // If any of the branch means are fixed, this won't work. double v1 = 0; try { scale_means_only_slice_function slice_levels_function(PP); double v2 = sample(PP,slice_levels_function, v1); //---------- Record Statistics --------------// Result result(2); result.totals[0] = std::abs(v2); result.totals[1] = slice_levels_function.count; Stats.inc(name,result); } catch (...) {} }
/// Propose three neighboring branch lengths all anti-correlated void change_3_branch_lengths(owned_ptr<Probability_Model>& P,MoveStats& Stats,int n) { Parameters* PP = P.as<Parameters>(); MCMC::Result result(2); const Tree& T = *PP->T; if (not T[n].is_internal_node()) return; //-------------- Find branches ------------------// vector<const_branchview> branches; append(T[n].branches_out(),branches); int b1 = branches[0].undirected_name(); int b2 = branches[1].undirected_name(); int b3 = branches[2].undirected_name(); //------------ Change coordinates ---------------// double T1 = T.branch(b1).length(); double T2 = T.branch(b2).length(); double T3 = T.branch(b3).length(); double S12 = T1 + T2; double S23 = T2 + T3; double S31 = T3 + T1; //----------- Propose new distances -------------// double sigma = loadvalue(P->keys,"log_branch_sigma",0.6)/2.0; double ratio = 1.0; double T1_ = T1; double T2_ = T2; double T3_ = T3; for(int i=0;i<20;i++) { double R12 = exp(gaussian(0,sigma)); double R23 = exp(gaussian(0,sigma)); double R31 = exp(gaussian(0,sigma)); double S12_ = S12 * R12; double S23_ = S23 * R23; double S31_ = S31 * R31; //---------------- Change back ------------------// T1_ = (S12_ + S31_ - S23_)/2.0; T2_ = (S12_ + S23_ - S31_)/2.0; T3_ = (S23_ + S31_ - S12_)/2.0; ratio = R12 * R23 * R31; if (T1_ > 0.0 and T2_ > 0.0 and T3_ > 0.0) break; } if (T1_ <= 0.0 or T2_ <= 0.0 or T3_ <= 0.0) return; //----------- Construct proposed Tree -----------// PP->set_root(n); owned_ptr<Probability_Model> P2 = P; P2.as<Parameters>()->setlength(b1,T1_); P2.as<Parameters>()->setlength(b2,T2_); P2.as<Parameters>()->setlength(b3,T3_); //--------- Do the M-H step if OK--------------// if (do_MH_move(P,P2,ratio)) { result.totals[0] = 1; result.totals[1] = abs(T1_-T1) + abs(T2_-T2) + abs(T3_-T3); } Stats.inc("3-branch-lengths",result); }
void scale_means_only(owned_ptr<Probability_Model>& P,MoveStats& Stats) { Parameters* PP = P.as<Parameters>(); // If any of the partition rates are fixed, then we're out of luck // FIXME - techincally, we could recompute likelihoods in just THOSE partitions :P // - also, I suppose, if they are fixed, then there is no mixing problem. for(int i=0;i<PP->n_branch_means();i++) if (PP->is_fixed(PP->branch_mean_index(i))) return; MCMC::Result result(2); //------------ Propose scaling ratio ------------// const double sigma = loadvalue(P->keys,"log_branch_mean_sigma",0.6); Bounds<double> b; for(int i=0; i<PP->n_branch_means(); i++) { Bounds<double> b2 = PP->get_bounds(PP->branch_mean_index(i)); double mu = PP->get_parameter_value_as<Double>(PP->branch_mean_index(i)); if (b2.has_lower_bound and b2.lower_bound > 0) { b2.has_lower_bound = true; b2.lower_bound = log(b2.lower_bound) - log(mu); } else b2.has_lower_bound = false; if (b2.has_upper_bound) b2.upper_bound = log(b2.upper_bound) - log(mu); b = b and b2; } double scale = gaussian(0,sigma); scale = wrap(scale, b); scale = exp(scale); //-------- Change branch lengths and mean -------// owned_ptr<Parameters> P2 = PP; #ifndef NDEBUG { owned_ptr<Parameters> P3 = P2; check_caching(*PP,*P3); } #endif SequenceTree& T2 = *P2->T; for(int b=0;b<T2.n_branches();b++) { const double length = T2.branch(b).length(); T2.branch(b).set_length(length/scale); } P2->tree_propagate(); for(int i=0;i<PP->n_branch_means();i++) P2->branch_mean_tricky(i, P2->get_parameter_value_as<Double>(P2->branch_mean_index(i)) * scale); #ifndef NDEBUG owned_ptr<Parameters> P3 = P2; P3->recalc_imodels(); P3->recalc_smodels(); efloat_t L1 = PP->likelihood(); efloat_t L2 = P3->likelihood(); double diff = std::abs(log(L1)-log(L2)); if (diff > 1.0e-9) { std::cerr<<"scale_mean_only: likelihood diff = "<<diff<<std::endl; std::abort(); } #endif //--------- Compute proposal ratio ---------// efloat_t p_ratio = pow(efloat_t(scale),P2->n_data_partitions()-T2.n_branches()); efloat_t a_ratio = P2->prior_no_alignment()/PP->prior_no_alignment()*p_ratio; #ifndef NDEBUG efloat_t a_ratio2 = P2->probability()/PP->probability()*p_ratio; double diff2 = std::abs(log(a_ratio2)-log(a_ratio)); if (diff2 > 1.0e-9) { std::cerr<<"scale_mean_only: a_ratio diff = "<<diff2<<std::endl; std::cerr<<"probability ratio = "<<log(P2->probability()/PP->probability())<<std::endl; std::cerr<<"likelihood ratio = "<<log(P2->likelihood()/PP->likelihood())<<std::endl; std::cerr<<"prior ratio = "<<log(P2->prior()/PP->prior())<<std::endl; std::cerr<<"prior ratio (no A)= "<<log(P2->prior_no_alignment()/PP->prior_no_alignment())<<std::endl; std::cerr<<"prior ratio ( A)= "<<log(P2->prior_alignment()/PP->prior_alignment())<<std::endl; std::cerr<<" a ratio = "<<log(a_ratio)<<std::endl; std::abort(); } #endif if (uniform() < double(a_ratio)) { P=P2; result.totals[0] = 1; result.totals[1] = std::abs(log(scale)); } Stats.inc("branch-means-only",result); }
void change_branch_length_and_T(owned_ptr<Probability_Model>& P,MoveStats& Stats,int b) { Parameters& PP = *P.as<Parameters>(); MCMC::Result result(5,0); result.counts[0] = 1; //------------- Propose new length --------------// const double length = PP.T->directed_branch(b).length(); double newlength = length; double ratio = branch_twiddle(newlength,PP.branch_mean()*0.6); //----- positive => propose length change -----// if (newlength >= 0) { result.counts[1] = 1; result.counts[3] = 1; //---------- Construct proposed Tree ----------// PP.select_root(b); owned_ptr<Probability_Model> P2 = P; P2.as<Parameters>()->setlength(b,newlength); //--------- Do the M-H step if OK--------------// if (do_MH_move(P,P2,ratio)) { result.totals[0] = 1; result.totals[1] = 1; result.totals[3] = std::abs(newlength - length); } } //----- negative => propose topology ---------// else { result.counts[2] = 1; result.counts[4] = 1; //----- Generate the Different Topologies ------// vector<Parameters> p(2,PP); SequenceTree& T2 = *p[1].T; vector<int> nodes = A5::get_nodes_random(T2,b); int b1 = T2.directed_branch(nodes[4],nodes[1]); int b2 = T2.directed_branch(nodes[5],nodes[2]); exchange_subtrees(T2,b1,b2); p[1].invalidate_subA_index_branch(b); vector<efloat_t> rho(2,1); rho[1] = ratio; //------ Sample the Different Topologies ------// int C = two_way_topology_sample(p,rho,b); if (C != -1) { PP = p[C]; } if (C > 0) { result.totals[0] = 1; result.totals[2] = 1; result.totals[4] = std::abs(length - newlength); } } Stats.inc("change_branch_length_and_T",result); }
void MH_Move::iterate(owned_ptr<Model>& P,MoveStats& Stats,int) { #ifndef NDEBUG clog<<" [MH] move = "<<name<<endl; #endif iterations++; owned_ptr<Model> P2 = P; double ratio = 1; try { ratio = (*proposal)(*P2); } catch (myexception& e) { std::ostringstream o; o<<" [MH] move = "<<name<<" (during proposal)\n"; e.prepend(o.str()); throw e; } int n = 1; Proposal2* p2 = dynamic_cast<Proposal2*>(&(*proposal)); int n_indices = -1; if (p2) { n_indices = p2->get_indices().size(); n = 2; } Result result(n); #ifndef NDEBUG show_parameters(std::cerr,*P); std::cerr<<P->probability()<<" = "<<P->likelihood()<<" + "<<P->prior()<<endl; std::cerr<<endl; show_parameters(std::cerr,*P2); std::cerr<<P2->probability()<<" = "<<P2->likelihood()<<" + "<<P2->prior(); std::cerr<<endl<<endl; #endif #ifndef NDEBUG // Check that we have not strayed outside the bounds. for(int i=0;i<P->n_parameters();i++) { if (not P->parameter_is_modifiable(i)) continue; if (not P->get_parameter_value(i).is_double()) continue; if (not P->has_bounds(i)) continue; Bounds<double> range = P->get_bounds(i); if (not range.in_range(P->get_parameter_value(i).as_double())) throw myexception()<<"Parameter "<<P->parameter_name(i)<<" = "<<P->get_parameter_value(i).as_double()<<" is NOT in range "<<range; if (not range.in_range(P2->get_parameter_value(i).as_double())) throw myexception()<<"Parameter "<<P->parameter_name(i)<<" = "<<P->get_parameter_value(i).as_double()<<" is NOT in range "<<range; } #endif // Accept or Reject if (accept_MH(*P,*P2,ratio)) { result.totals[0] = 1; if (n == 2) { int first_index = p2->get_indices()[0]; if (n_indices == 1 and P->get_parameter_value(first_index).is_double()) { double v1 = P->get_parameter_value(first_index).as_double(); double v2 = P2->get_parameter_value(first_index).as_double(); // cerr<<"v1 = "<<v1<<" v2 = "<<v2<<"\n"; result.totals[1] = std::abs(v2-v1); } else if (n_indices > 1 and P->get_parameter_value(first_index).is_double()) //currently this can only be a dirichlet proposal { double total = 0; for(int i=0;i<n_indices;i++) { int j = p2->get_indices()[i]; double v1 = P->get_parameter_value(j).as_double(); double v2 = P2->get_parameter_value(j).as_double(); total += std::abs(log(v1/v2)); } result.totals[1] = total; } } P = P2; } Stats.inc(name,result); }