Create the TreeManip class

There are benefits to keeping the Tree and Node classes simple, so we will create a TreeManip class that will own, manage and manipulate a Tree object. Rather than call the createTestTree() function of Tree, we will move that function to TreeManip. TreeManip will also eventually have functions to create a standard Newick description string, build a Tree from a Newick description, and perform modifications to a Tree needed during Metropolis (MCMC) proposals.

First, create the TreeManip class by creating a new header file named tree_manip.hpp and populating it with the following code:

#pragma once

#include <set>
#include <stack>
#include <boost/format.hpp>
#include <boost/regex.hpp>
#include <boost/lexical_cast.hpp>
#include "node.hpp"
#include "tree.hpp"

namespace strom
    template <class T>
    class TreeManip

            typename Tree<T>::SharedPtr getTree();
            void                        createTestTree();
	    void                        clear();


            typename Tree<T>::SharedPtr _tree;

	    typedef boost::shared_ptr< TreeManip<T> > SharedPtr;

    // This is where function bodies go

Class declarations like this should look familiar because there are many similarities of this class declaration to those we created for Tree and Node. Inside the strom namespace, we have created a templated class named TreeManip that has a constructor, destructor, three public functions, a data member named _tree, and a type definition that will allow us to create shared pointers to TreeManip object.

We still need to define bodies for each of the functions in the class declaration above. Here are the bodies for the constructor and destructor. These functions currently do nothing except announce that a TreeManip object is being created or destroyed. These should go after the semicolon (;) ending the class declaration but before the curly bracket (}) that closes the namespace:

template <class T>
inline TreeManip<T>::TreeManip()
    std::cerr << "Constructing a TreeManip" << std::endl;

template <class T>
inline TreeManip<T>::~TreeManip()
    std::cerr << "Destroying a TreeManip" << std::endl;

The clear() function resets the _tree data member. Resetting a shared pointer causes it to no longer point to any object. If this was the last shared pointer holding onto the Tree object, the Tree object will be deleted (and you should see its destructor report that it has been called):

template <class T>
inline void TreeManip<T>::clear()

The getTree() function simply returns a shared pointer to the Tree object being managed by this TreeManip object:

template <class T>
inline typename Tree<T>::SharedPtr TreeManip<T>::getTree()
    return _tree;

Finally, the createTestTree() function is nearly identical to the function of the same name in the Tree class. One difference is that we must create a Tree first, and data members of the Tree class (such as _nodes, _preorder, and _is_rooted) must be accessed through the TreeManip object’s _tree pointer:

template <class T>
inline void TreeManip<T>::createTestTree()
    _tree = typename Tree<T>::SharedPtr(new Tree<T>());

    T * root_node       = &_tree->_nodes[0];
    T * first_internal  = &_tree->_nodes[1];
    T * second_internal = &_tree->_nodes[2];
    T * first_leaf      = &_tree->_nodes[3];
    T * second_leaf     = &_tree->_nodes[4];
    T * third_leaf      = &_tree->_nodes[5];

    // Here is the structure of the tree 
    // (numbers are edge lengths):
    // first_leaf second_leaf   third_leaf
    //      \         /            /
    //       \ 0.1   / 0.1        /
    //        \     /            /
    //     second_internal      / 0.2
    //            \            /
    //             \ 0.1      /
    //              \        /
    //            first_internal
    //                  |
    //                  | 0.1
    //                  |
    //              root_node
    root_node->_parent = 0;
    root_node->_left_child = first_internal;
    root_node->_right_sib = 0;
    root_node->_number = 0;
    root_node->_name = "root node";
    root_node->_edge_length = 0.0;

    first_internal->_parent = root_node;
    first_internal->_left_child = second_internal;
    first_internal->_right_sib = 0;
    first_internal->_number = 1;
    first_internal->_name = "first internal node";
    first_internal->_edge_length = 0.1;

    second_internal->_parent = first_internal;
    second_internal->_left_child = first_leaf;
    second_internal->_right_sib = third_leaf;
    second_internal->_number = 2;
    second_internal->_name = "second internal node";
    second_internal->_edge_length = 0.1;

    first_leaf->_parent = second_internal;
    first_leaf->_left_child = 0;
    first_leaf->_right_sib = second_leaf;
    first_leaf->_number = 3;
    first_leaf->_name = "first leaf";
    first_leaf->_edge_length = 0.1;

    second_leaf->_parent = second_internal;
    second_leaf->_left_child = 0;
    second_leaf->_right_sib = 0;
    second_leaf->_number = 4;
    second_leaf->_name = "second leaf";
    second_leaf->_edge_length = 0.1;

    third_leaf->_parent = first_internal;
    third_leaf->_left_child = 0;
    third_leaf->_right_sib = 0;
    third_leaf->_number = 5;
    third_leaf->_name = "third leaf";
    third_leaf->_edge_length = 0.1;

    _tree->_is_rooted = true;
    _tree->_nleaves = 3;


Before moving on, edit your Tree class (file tree.hpp) and delete all traces of createTestTree(). We no longer need Tree to have this capability because we can now ask TreeManip to create a test tree.

Also, edit your Node class (file node.hpp) and uncomment the lines making TreeManip a friend class of Node. This will just involve removing the initial // from two lines in tree.hpp.

The Tree class will need to be similarly modified so that TreeManip is a friend of Tree. I’ve indicated the two lines in tree.hpp that need to be uncommented below in bold, blue text:

#pragma once

#include <boost/shared_ptr.hpp>
#include <iostream>
#include <vector>

namespace strom

    template<class T> class TreeManip;
    //template<class T> class Likelihood;

    template <class T>
    class Tree

        friend class TreeManip<T>;
        //friend class Likelihood<T>;



		T *                 getRoot();
		void                clear();

		bool                _is_rooted;
		unsigned            _nleaves;
		std::vector<T *>    _preorder;
		std::vector<T>      _nodes; 
		typedef boost::shared_ptr< Tree<T> > SharedPtr;