To test both the buildFromNewick
and the makeNewick
function, change main.cpp to look like this:
#include <iostream>
#include <string>
#include "node.hpp"
#include "tree.hpp"
#include "tree_manip.hpp"
#include "xstrom.hpp"
using namespace strom;
const double Node::_smallest_edge_length = 1.0e-12;
int main(int argc, const char * argv[]) {
std::cout << "Starting..." << std::endl;
TreeManip tm;
std::string newick = std::string("(1:0.3,2:0.3,(3:0.2,(4:0.1,5:0.1):0.1):0.1)");
std::cout << "Input: " << newick << std::endl;
try {
tm.buildFromNewick(newick, false, false);
std::cout << "Output: " << tm.makeNewick(3) << std::endl;
tm.rerootAtNodeNumber(4);
std::cout << "Output: " << tm.makeNewick(3) << std::endl;
}
catch (XStrom x) {
std::cout << "Error: " << x.what() << std::endl;
}
std::cout << "\nFinished!" << std::endl;
return 0;
}
The main function now creates a tree from the newick string
(1:0.3,2:0.3,(3:0.2,(4:0.1,5:0.1):0.1):0.1)
and then uses the makeNewick
function to turn the tree in memory into a newick string, which is output. The program is working correctly if the output string represents the same tree as the input string (note that the number of decimal places used to depict edge lengths will differ, but the tree descriptions should depict exactly the same tree topology and edge lengths).
These two lines in main.cpp test whether the rerootAtNodeNumber function works correctly.
tm.rerootAtNodeNumber(4);
std::cout << "Output: " << tm.makeNewick(3) << std::endl;
These lines ask the program to reroot using the node having _number
equal to 4, which is actually the number labeled 5 in the newick string.
Here is the output that your program should produce. See the next section if you have problems running the program.
Starting...
Constructing a TreeManip
Input: (1:0.3,2:0.3,(3:0.2,(4:0.1,5:0.1):0.1):0.1)
Constructing a Tree
Creating Node object
Creating Node object
Creating Node object
Creating Node object
Creating Node object
Creating Node object
Creating Node object
Creating Node object
Output: (1:0.300,2:0.300,(3:0.200,(4:0.100,5:0.100):0.100):0.100)
Output: (5:0.100,4:0.100,(3:0.200,(2:0.300,1:0.300):0.100):0.100)
Finished!
Destroying a TreeManip
Destroying a Tree
Destroying Node object
Destroying Node object
Destroying Node object
Destroying Node object
Destroying Node object
Destroying Node object
Destroying Node object
Destroying Node object
assert(!nd->_left_child)
…Assert statements test assumptions that you are making as you write source code. Any time you find yourself thinking “I’m pretty sure that will never happen”, then it is probably time to use an assert
statement to ensure that, if it does happen, you know about it and can find where it happened and under what circumstances it happened. Assert statements disappear in optimized code, so you will only see these trip if you are running the debug (non-optimized) version of your program (usually inside the IDE).
The fact that assert
statements do not end up in the optimized (non-debug) version of your program means that you should use exceptions rather than asserts for assumptions you are making about the behavior of users of your program. Asserts help protect your program from yourself; exceptions help protect your program from your users.
If your program trips the assert(!nd->_left_child);
inside the TreeManip::buildFromNewick
function, then almost certainly what has happened is that you’ve not removed all traces of Tree::createTestTree()
, which you were instructed to do in the very last (“Before moving on…”) section of the page Create the TreeManip class. The problem is that your Tree
constructor is building a default tree every time it is called, so you are never starting from a clean slate with respect to the tree that you are building. Thus, you must remove the call to createTestTree()
in the Tree::Tree
constructor and reinstate the clear()
function there.
If you would like to test the exception mechanism, try introducing an error in the newick tree description. For example, changing taxon “3” to “Z”. This will create an exception because only newick descriptions with taxon names that can be converted to positive integers are allowed:
std::string newick = std::string("(1:0.3,2:0.3,(Z:0.2,(4:0.1,5:0.1):0.1):0.1)");
Running the program now should produce the following error message:
Error: node name (Z) not interpretable as a positive integer
(Be sure to change the “Z” back to a “3” before continuing.)