A toolkit for working with phylogenetic data.
v0.24.0
tree/tree.cpp
Go to the documentation of this file.
1 /*
2  Genesis - A toolkit for working with phylogenetic data.
3  Copyright (C) 2014-2018 Lucas Czech and HITS gGmbH
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  Contact:
19  Lucas Czech <lucas.czech@h-its.org>
20  Exelixis Lab, Heidelberg Institute for Theoretical Studies
21  Schloss-Wolfsbrunnenweg 35, D-69118 Heidelberg, Germany
22 */
23 
31 #include "genesis/tree/tree.hpp"
32 
34 
35 #include <cassert>
36 #include <stdexcept>
37 #include <typeinfo>
38 #include <type_traits>
39 
40 namespace genesis {
41 namespace tree {
42 
43 // =================================================================================================
44 // Construction and Rule of Five
45 // =================================================================================================
46 
47 static_assert( std::is_move_constructible<Tree>::value, "Tree is not move constructible." );
48 static_assert( std::is_move_assignable<Tree>::value, "Tree is not move assignable." );
49 
50 Tree::Tree( const Tree& other )
51 {
52  // Get a copy of the topology. (Copy swap idiom.)
53  auto res = other.clone_topology();
54 
55  // Copy data.
56  for( size_t i = 0; i < res.links_.size(); ++i ) {
57  // res.links_[i]->data = other.links_[i]->data;
58  }
59  for( size_t i = 0; i < res.nodes_.size(); ++i ) {
60  if( other.node_at(i).has_data() ) {
61  res.node_at(i).reset_data( other.node_at(i).data_ptr()->clone() );
62  }
63 
64  // Some assertions.
65  if( res.node_at(i).has_data() && other.node_at(i).has_data() ) {
66  auto const& res_data = *res.node_at(i).data_ptr();
67  auto const& oth_data = *other.node_at(i).data_ptr();
68  (void) res_data;
69  (void) oth_data;
70  assert( typeid( res_data ) == typeid( oth_data ));
71  } else {
72  assert( ! res.node_at(i).has_data() && ! other.node_at(i).has_data() );
73  }
74  }
75  for( size_t i = 0; i < res.edges_.size(); ++i ) {
76  if( other.edge_at(i).has_data() ) {
77  res.edge_at(i).reset_data( other.edge_at(i).data_ptr()->clone() );
78  }
79 
80  // Some assertions.
81  if( res.edges_[i]->has_data() && other.edge_at(i).has_data() ) {
82  auto const& res_data = *res.edge_at(i).data_ptr();
83  auto const& oth_data = *other.edge_at(i).data_ptr();
84  (void) res_data;
85  (void) oth_data;
86  assert( typeid( res_data ) == typeid( oth_data ));
87  } else {
88  assert( ! res.edge_at(i).has_data() && ! other.edge_at(i).has_data() );
89  }
90  }
91 
92  // Swap with the (currently empty) content of this tree.
93  res.swap( *this );
94 }
95 
96 Tree& Tree::operator = ( Tree const& other )
97 {
98  // Check for self assignment. Just in case.
99  if( &other == this ) {
100  return *this;
101  }
102 
103  // Copy-swap-idiom.
104  Tree temp( other );
105  temp.swap( *this );
106  return *this;
107 }
108 
110 {
111  // Prepare resulting tree.
112  auto res = Tree();
113  res.links_.resize( link_count() );
114  res.nodes_.resize( node_count() );
115  res.edges_.resize( edge_count() );
116 
117  // Create all objects. We need two loops per array, because the pointers have to exist
118  // in order to be linked to each other.
119  for( size_t i = 0; i < links_.size(); ++i ) {
120  res.links_[i] = utils::make_unique< TreeLink >();
121  }
122  for( size_t i = 0; i < nodes_.size(); ++i ) {
123  res.nodes_[i] = utils::make_unique< TreeNode >();
124  }
125  for( size_t i = 0; i < edges_.size(); ++i ) {
126  res.edges_[i] = utils::make_unique< TreeEdge >();
127  }
128 
129  // Set all pointers for the topology in a second round of loops.
130  for( size_t i = 0; i < links_.size(); ++i ) {
131  auto const& cur_link = link_at(i);
132  assert( cur_link.index() == i );
133 
134  res.links_[i]->reset_index( i );
135  res.links_[i]->reset_next( res.links_[ cur_link.next().index() ].get() );
136  res.links_[i]->reset_outer( res.links_[ cur_link.outer().index() ].get() );
137  res.links_[i]->reset_node( res.nodes_[ cur_link.node().index() ].get() );
138  res.links_[i]->reset_edge( res.edges_[ cur_link.edge().index() ].get() );
139  }
140  for( size_t i = 0; i < nodes_.size(); ++i ) {
141  auto const& cur_node = node_at(i);
142  assert( cur_node.index() == i );
143 
144  res.nodes_[i]->reset_index( i );
145  res.nodes_[i]->reset_primary_link( res.links_[ cur_node.link().index() ].get() );
146  }
147  for( size_t i = 0; i < edges_.size(); ++i ) {
148  auto const& cur_edge = edge_at(i);
149  assert( cur_edge.index() == i );
150 
151  res.edges_[i]->reset_index( i );
152  res.edges_[i]->reset_primary_link( res.links_[ cur_edge.primary_link().index() ].get() );
153  res.edges_[i]->reset_secondary_link( res.links_[ cur_edge.secondary_link().index() ].get() );
154  }
155 
156  // Don't forget to set the root link.
157  res.root_link_ = res.links_[ root_link_->index() ].get();
158  return res;
159 }
160 
161 void Tree::swap( Tree& other )
162 {
163  using std::swap;
164 
165  swap( root_link_, other.root_link_ );
166 
167  swap( links_, other.links_ );
168  swap( nodes_, other.nodes_ );
169  swap( edges_, other.edges_ );
170 }
171 
173 {
174  root_link_ = nullptr;
175  links_.clear();
176  nodes_.clear();
177  edges_.clear();
178 }
179 
180 // =================================================================================================
181 // Data Accessors
182 // =================================================================================================
183 
185 {
186  assert( root_link->index() < links_.size() );
187  assert( links_[root_link->index()].get() == root_link );
188  root_link_ = root_link;
189  return *this;
190 }
191 
193 {
194  return links_;
195 }
196 
198 {
199  return nodes_;
200 }
201 
203 {
204  return edges_;
205 }
206 
207 } // namespace tree
208 } // namespace genesis
ContainerType< TreeEdge > EdgeContainerType
Alias for the container type that is used to store TreeEdges.
Definition: tree/tree.hpp:125
virtual std::unique_ptr< BaseEdgeData > clone() const
Polymorphically copy an instance of this class. Use instead of copy constructor.
Definition: edge_data.hpp:134
bool has_data() const
Return true if the TreeEdge has a data object assigned to it.
Definition: edge.hpp:182
void swap(SequenceSet &lhs, SequenceSet &rhs)
size_t edge_count() const
Return the number of TreeEdges of the Tree.
Definition: tree/tree.hpp:272
Container namespace for all symbols of genesis in order to keep them separate when used as a library...
Provides some valuable additions to STD.
ContainerType< TreeNode > NodeContainerType
Alias for the container type that is used to store TreeNodes.
Definition: tree/tree.hpp:120
Tree clone_topology() const
Return a Tree with the same topology, but without any data.
Definition: tree/tree.cpp:109
BaseEdgeData * data_ptr()
Return a pointer to the data.
Definition: edge.hpp:246
Tree & operator=(Tree const &other)
Assignment operator.
Definition: tree/tree.cpp:96
Class for representing phylogenetic trees.
Definition: tree/tree.hpp:97
bool has_data() const
Return true if the TreeNode has a data object assigned to it.
Definition: node.hpp:168
size_t link_count() const
Return the number of TreeLinks of the Tree.
Definition: tree/tree.hpp:256
Tree & reset_root_link(TreeLink *root_link)
Reset the link that is considered to be the root of the Tree.
Definition: tree/tree.cpp:184
TreeNode & node_at(size_t index)
Return the TreeNode at a certain index.
Definition: tree/tree.hpp:220
void swap(Tree &other)
Swap.
Definition: tree/tree.cpp:161
TreeLink & root_link()
Return the TreeLink at the current root of the Tree.
Definition: tree/tree.hpp:284
LinkContainerType & expose_link_container()
Get the container that stores all TreeLinks of the Tree.
Definition: tree/tree.cpp:192
TreeEdge & edge_at(size_t index)
Return the TreeEdge at a certain index.
Definition: tree/tree.hpp:238
size_t node_count() const
Return the number of TreeNodes of the Tree.
Definition: tree/tree.hpp:264
TreeLink & link_at(size_t index)
Return the TreeLink at a certain index.
Definition: tree/tree.hpp:202
void clear()
Deletes all data of the tree, including all links, nodes and edges.
Definition: tree/tree.cpp:172
virtual std::unique_ptr< BaseNodeData > clone() const
Polymorphically copy an instance of this class. Use instead of copy constructor.
Definition: node_data.hpp:134
ContainerType< TreeLink > LinkContainerType
Alias for the container type that is used to store TreeLinks.
Definition: tree/tree.hpp:115
Header of Tree class.
TreeNode & reset_data(std::unique_ptr< BaseNodeData > data)
Reset the data pointer of this TreeNode.
Definition: node.hpp:290
EdgeContainerType & expose_edge_container()
Get the container that stores all TreeEdges of the Tree.
Definition: tree/tree.cpp:202
BaseNodeData * data_ptr()
Return a pointer to the data.
Definition: node.hpp:232
NodeContainerType & expose_node_container()
Get the container that stores all TreeNodes of the Tree.
Definition: tree/tree.cpp:197