We will need to make one modification to the TreeUpdater
class. Specificaly, we need to provide a special case proposal for the case in which the current tree is the star tree. The star tree (only one internal node) is a special case because it does not contain a 3-edge segment to modify. In the case of the star tree, we will simply adjust two randomly-chosen edge proportions. Add the highlighted starTreeMove
function prototype as well as the _star_tree_move
data member to the class declaration
class TreeUpdater : public Updater {
friend class Chain;
public:
typedef std::shared_ptr< TreeUpdater > SharedPtr;
TreeUpdater();
~TreeUpdater();
virtual double calcLogPrior();
private:
virtual void revert();
virtual void proposeNewState();
<span style="color:#0000ff"><strong>void starTreeMove();</strong></span>
virtual void reset();
double _orig_edgelen_top;
double _orig_edgelen_middle;
double _orig_edgelen_bottom;
unsigned _case;
bool _topology_changed;
<span style="color:#0000ff"><strong>bool _star_tree_move;</strong></span>
Node * _x;
Node * _y;
Node * _a;
Node * _b;
};
Now add the following function body to tree_updater.hpp.
inline void TreeUpdater::starTreeMove() {
// Choose focal 2-edge segment to modify
_orig_edgelen_middle = 0.0;
// Choose the first edge
_a = _tree_manipulator->randomChild(_lot, _x, 0, false);
_orig_edgelen_top = _a->getEdgeLength();
// Choose the second edge
_b = _tree_manipulator->randomChild(_lot, _x, _a, true);
if (!_b)
_b = _x;
_orig_edgelen_bottom = _b->getEdgeLength();
// Note that _a must be a child of _x, but _b may either be a different child of _x or _x itself
double u = _lot->uniform();
double new_edgelen_top = u*(_orig_edgelen_top + _orig_edgelen_bottom);
double new_edgelen_bottom = (1.0 - u)*(_orig_edgelen_top + _orig_edgelen_bottom);
// Hastings ratio and Jacobian are both 1 under Gamma-Dirichlet parameterization
_log_hastings_ratio = 0.0;
_log_jacobian = 0.0;
// Change edge lengths and flag partials and transition matrices for recalculation
_tree_manipulator->selectPartialsHereToRoot(_x);
_a->setEdgeLength(new_edgelen_top);
_a->selectTMatrix();
_b->setEdgeLength(new_edgelen_bottom);
_b->selectTMatrix();
}
Call the starTreeMove
function near the beginning of the proposeNewState function if the current tree is the star tree:
inline void TreeUpdater::proposeNewState() {
_case = 0;
_topology_changed = false;
assert(!_tree_manipulator->getTree()->isRooted());
// Choose random internal node x that is not the root and has parent y that is also not the root.
// After choosing x (and thus y), choose a and b randomly to create a contiguous 3-edge segment.
//
// a
// \ | /
// \|/
// x
// \ | /
// \|/
// y
// |
// |
// b
//
<span style="color:#0000ff"><strong>// For the star tree, there is only one internal node. In this case, only choose</strong></span>
<span style="color:#0000ff"><strong>// two edges and modify them (no change in tree topology is possible)</strong></span>
<span style="color:#0000ff"><strong>//</strong></span>
<span style="color:#0000ff"><strong>// a</strong></span>
<span style="color:#0000ff"><strong>// \ | /</strong></span>
<span style="color:#0000ff"><strong>// \|/</strong></span>
<span style="color:#0000ff"><strong>// x</strong></span>
<span style="color:#0000ff"><strong>// |</strong></span>
<span style="color:#0000ff"><strong>// |</strong></span>
<span style="color:#0000ff"><strong>// b</strong></span>
<span style="color:#0000ff"><strong>//</strong></span>
_x = _tree_manipulator->randomInternalEdge(_lot);
_orig_edgelen_middle = _x->getEdgeLength();
<span style="color:#0000ff"><strong>// The only child of the root node will be chosen only if the tree equals the star tree</strong></span>
<span style="color:#0000ff"><strong>// in which case we want to perform a starTreeMove rather than Larget-Simon</strong></span>
<span style="color:#0000ff"><strong>_star_tree_move = false;</strong></span>
<span style="color:#0000ff"><strong>if (_x->getParent() && !_x->getParent()->getParent()) {</strong></span>
<span style="color:#0000ff"><strong>_star_tree_move = true;</strong></span>
<span style="color:#0000ff"><strong>starTreeMove();</strong></span>
<span style="color:#0000ff"><strong>return;</strong></span>
<span style="color:#0000ff"><strong>}</strong></span>
_y = _x->getParent();
//...
Finally, add a section to the TreeUpdater::revert
function to revert a star tree move, if the current tree is the star tree.
inline void TreeUpdater::revert() {
<span style="color:#0000ff"><strong>if (_star_tree_move) {</strong></span>
<span style="color:#0000ff"><strong>_a->setEdgeLength(_orig_edgelen_top);</strong></span>
<span style="color:#0000ff"><strong>_b->setEdgeLength(_orig_edgelen_bottom);</strong></span>
<span style="color:#0000ff"><strong>}</strong></span>
<span style="color:#0000ff"><strong>else {</strong></span>
assert(_case > 0 && _case < 9);
if (_case == 2 || _case == 6)
_tree_manipulator->LargetSimonSwap(_a, _b);
else if (_case == 1 || _case == 5)
_tree_manipulator->LargetSimonSwap(_b, _a);
_a->setEdgeLength(_orig_edgelen_top);
_x->setEdgeLength(_orig_edgelen_middle);
if (_case == 1 || _case == 3 || _case == 5 || _case == 7)
_b->setEdgeLength(_orig_edgelen_bottom); // not actually necessary for case 3
else
_y->setEdgeLength(_orig_edgelen_bottom); // not actually necessary for case 4
<span style="color:#0000ff"><strong>}</strong></span>
}