A library for working with phylogenetic and population genetic data.
v0.27.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
genesis::placement::swap
void swap(Sample &lhs, Sample &rhs)
Definition: sample.cpp:104
genesis::tree::Tree::Tree
Tree()=default
genesis::tree::Tree::node_count
size_t node_count() const
Return the number of TreeNodes of the Tree.
Definition: tree/tree.hpp:264
genesis::tree::TreeEdge::has_data
bool has_data() const
Return true if the TreeEdge has a data object assigned to it.
Definition: edge.hpp:182
genesis::tree::Tree::link_count
size_t link_count() const
Return the number of TreeLinks of the Tree.
Definition: tree/tree.hpp:256
genesis::tree::Tree::expose_link_container
LinkContainerType & expose_link_container()
Get the container that stores all TreeLinks of the Tree.
Definition: tree/tree.cpp:192
tree.hpp
Header of Tree class.
genesis::tree::Tree::expose_node_container
NodeContainerType & expose_node_container()
Get the container that stores all TreeNodes of the Tree.
Definition: tree/tree.cpp:197
genesis::tree::Tree::node_at
TreeNode & node_at(size_t index)
Return the TreeNode at a certain index.
Definition: tree/tree.hpp:220
genesis::tree::Tree::edge_at
TreeEdge & edge_at(size_t index)
Return the TreeEdge at a certain index.
Definition: tree/tree.hpp:238
std.hpp
Provides some valuable additions to STD.
genesis::tree::Tree
Class for representing phylogenetic trees.
Definition: tree/tree.hpp:97
genesis::tree::Tree::reset_root_link
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
genesis::tree::TreeNode::has_data
bool has_data() const
Return true if the TreeNode has a data object assigned to it.
Definition: tree/tree/node.hpp:168
genesis::tree::Tree::root_link
TreeLink & root_link()
Return the TreeLink at the current root of the Tree.
Definition: tree/tree.hpp:284
genesis::tree::Tree::clear
void clear()
Deletes all data of the tree, including all links, nodes and edges.
Definition: tree/tree.cpp:172
genesis::tree::BaseEdgeData::clone
virtual std::unique_ptr< BaseEdgeData > clone() const
Polymorphically copy an instance of this class. Use instead of copy constructor.
Definition: edge_data.hpp:134
genesis::tree::Tree::LinkContainerType
ContainerType< TreeLink > LinkContainerType
Alias for the container type that is used to store TreeLinks.
Definition: tree/tree.hpp:115
genesis::tree::Tree::swap
void swap(Tree &other)
Swap.
Definition: tree/tree.cpp:161
genesis::tree::Tree::expose_edge_container
EdgeContainerType & expose_edge_container()
Get the container that stores all TreeEdges of the Tree.
Definition: tree/tree.cpp:202
genesis
Container namespace for all symbols of genesis in order to keep them separate when used as a library.
Definition: placement/formats/edge_color.cpp:42
genesis::tree::Tree::operator=
Tree & operator=(Tree const &other)
Assignment operator.
Definition: tree/tree.cpp:96
genesis::tree::TreeEdge::data_ptr
BaseEdgeData * data_ptr()
Return a pointer to the data.
Definition: edge.hpp:246
genesis::tree::Tree::clone_topology
Tree clone_topology() const
Return a Tree with the same topology, but without any data.
Definition: tree/tree.cpp:109
genesis::tree::TreeNode::reset_data
TreeNode & reset_data(std::unique_ptr< BaseNodeData > data)
Reset the data pointer of this TreeNode.
Definition: tree/tree/node.hpp:290
genesis::tree::BaseNodeData::clone
virtual std::unique_ptr< BaseNodeData > clone() const
Polymorphically copy an instance of this class. Use instead of copy constructor.
Definition: node_data.hpp:134
genesis::tree::Tree::EdgeContainerType
ContainerType< TreeEdge > EdgeContainerType
Alias for the container type that is used to store TreeEdges.
Definition: tree/tree.hpp:125
genesis::tree::Tree::NodeContainerType
ContainerType< TreeNode > NodeContainerType
Alias for the container type that is used to store TreeNodes.
Definition: tree/tree.hpp:120
genesis::tree::Tree::link_at
TreeLink & link_at(size_t index)
Return the TreeLink at a certain index.
Definition: tree/tree.hpp:202
genesis::tree::TreeNode::data_ptr
BaseNodeData * data_ptr()
Return a pointer to the data.
Definition: tree/tree/node.hpp:232
genesis::tree::Tree::edge_count
size_t edge_count() const
Return the number of TreeEdges of the Tree.
Definition: tree/tree.hpp:272