A library for working with phylogenetic and population genetic data.
v0.32.0
tree/function/operators.cpp
Go to the documentation of this file.
1 /*
2  Genesis - A toolkit for working with phylogenetic data.
3  Copyright (C) 2014-2024 Lucas Czech
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@sund.ku.dk>
20  University of Copenhagen, Globe Institute, Section for GeoGenetics
21  Oster Voldgade 5-7, 1350 Copenhagen K, Denmark
22 */
23 
32 
39 
40 #include <ostream>
41 
42 #ifdef GENESIS_OPENMP
43 # include <omp.h>
44 #endif
45 
46 namespace genesis {
47 namespace tree {
48 
49 // =================================================================================================
50 // Conversion
51 // =================================================================================================
52 
54  Tree const& source,
55  std::function< std::unique_ptr<BaseNodeData>( BaseNodeData const& node_data )> node_data_converter,
56  std::function< std::unique_ptr<BaseEdgeData>( BaseEdgeData const& edge_data )> edge_data_converter
57 ) {
58  // Copy the topology. All data pointers of the new tree are nullptrs.
59  auto res = source.clone_topology();
60 
61  // Convert data where there is data.
62  for( size_t i = 0; i < res.node_count(); ++i ) {
63  if( source.node_at(i).has_data() ) {
64  res.node_at(i).reset_data( node_data_converter( *source.node_at(i).data_ptr() ));
65  }
66  }
67  for( size_t i = 0; i < res.edge_count(); ++i ) {
68  if( source.edge_at(i).has_data() ) {
69  res.edge_at(i).reset_data( edge_data_converter( *source.edge_at(i).data_ptr() ));
70  }
71  }
72 
73  return res;
74 }
75 
76 // =================================================================================================
77 // Equality and Identity
78 // =================================================================================================
79 
80 bool equal(
81  Tree const& lhs,
82  Tree const& rhs,
83  std::function<bool ( TreeNode const&, TreeNode const&) > node_comparator,
84  std::function<bool ( TreeEdge const&, TreeEdge const&) > edge_comparator
85 ) {
86  // Check array sizes.
87  if (lhs.link_count() != rhs.link_count() ||
88  lhs.node_count() != rhs.node_count() ||
89  lhs.edge_count() != rhs.edge_count()
90  ) {
91  return false;
92  }
93 
94  // do a preorder traversal on both trees in parallel
95  auto it_l = preorder(lhs).begin();
96  auto it_r = preorder(rhs).begin();
97  for (
98  ;
99  it_l != preorder(lhs).end() && it_r != preorder(rhs).end();
100  ++it_l, ++it_r
101  ) {
102  if( degree( it_l.node() ) != degree( it_r.node() ) ||
103  !node_comparator( it_l.node(), it_r.node() ) ||
104  !edge_comparator( it_l.edge(), it_r.edge() )
105  ) {
106  return false;
107  }
108  }
109 
110  // check whether we are done with both trees
111  if( it_l != preorder(lhs).end() || it_r != preorder(rhs).end() ) {
112  return false;
113  }
114 
115  return true;
116 }
117 
118 bool equal(
119  std::vector<Tree> const& trees,
120  std::function<bool ( TreeNode const&, TreeNode const&) > node_comparator,
121  std::function<bool ( TreeEdge const&, TreeEdge const&) > edge_comparator
122 ) {
123  // If all pairs of two adjacent trees are equal, all of them are.
124  // Thus, we do not need a complete pairwise comparision.
125  // In order to also accelarate via OpenMP, we need a flag instead of immediately
126  // returning on finding a false. We cannot break in OpenMP, but we can skip (which is fast),
127  // if we already know the result.
128 
129  bool result = true;
130  #pragma omp parallel for
131  for (size_t i = 1; i < trees.size(); i++) {
132  if( ! result ) {
133  continue;
134  }
135 
136  if( ! equal( trees[i-1], trees[i], node_comparator, edge_comparator )) {
137  result = false;
138  }
139  }
140  return result;
141 }
142 
143 /* *
144  * @brief Compares two trees for equality using the respective comparision operators for their nodes
145  * and edges.
146  *
147  * This method is mainly a shortcut for the other equal function, where the comparator functionals
148  * are instanciated using the default comparision operators of the tree's data.
149  */
150 // bool equal( Tree const& lhs, Tree const& rhs)
151 // {
152 // auto node_comparator = [] (
153 // TreeNode const& node_l,
154 // TreeNode const& node_r
155 // ) {
156 // return node_l == node_r;
157 // };
158 //
159 // auto edge_comparator = [] (
160 // TreeEdge const& edge_l,
161 // TreeEdge const& edge_r
162 // ) {
163 // return edge_l == edge_r;
164 // };
165 //
166 // return equal<TreeTypeL, TreeTypeR>(lhs, rhs, node_comparator, edge_comparator);
167 // }
168 
169 bool identical_topology( Tree const& lhs, Tree const& rhs, bool identical_indices )
170 {
171  auto node_comparator = [ &identical_indices ] (
172  TreeNode const& node_l,
173  TreeNode const& node_r
174  ) {
175  if( identical_indices && node_l.index() != node_r.index() ) {
176  return false;
177  }
178  return true;
179  };
180 
181  auto edge_comparator = [ &identical_indices ] (
182  TreeEdge const& edge_l,
183  TreeEdge const& edge_r
184  ) {
185  if( identical_indices && edge_l.index() != edge_r.index() ) {
186  return false;
187  }
188  return true;
189  };
190 
191  return equal( lhs, rhs, node_comparator, edge_comparator );
192 }
193 
194 bool identical_topology( std::vector<Tree> const& trees, bool identical_indices )
195 {
196  // If all pairs of two adjacent trees have same the topology, all of them have.
197  // Thus, we do not need a complete pairwise comparision.
198  // In order to also accelarate via OpenMP, we need a flag instead of immediately
199  // returning on finding a false. We cannot break in OpenMP, but we can skip (which is fast),
200  // if we already know the result.
201 
202  bool result = true;
203  #pragma omp parallel for
204  for (size_t i = 1; i < trees.size(); i++) {
205  if( ! result ) {
206  continue;
207  }
208 
209  if( ! identical_topology( trees[i-1], trees[i], identical_indices )) {
210  result = false;
211  }
212  }
213  return result;
214 }
215 
216 // =================================================================================================
217 // Element Ownership Checks
218 // =================================================================================================
219 
220 bool belongs_to( Tree const& tree, TreeNode const& node )
221 {
222  return node.index() < tree.node_count() && &tree.node_at( node.index() ) == &node;
223 }
224 
225 bool belongs_to( TreeNode const& node, Tree const& tree )
226 {
227  return node.index() < tree.node_count() && &tree.node_at( node.index() ) == &node;
228 }
229 
230 bool belongs_to( Tree const& tree, TreeEdge const& edge )
231 {
232  return edge.index() < tree.edge_count() && &tree.edge_at( edge.index() ) == &edge;
233 }
234 
235 bool belongs_to( TreeEdge const& edge, Tree const& tree )
236 {
237  return edge.index() < tree.edge_count() && &tree.edge_at( edge.index() ) == &edge;
238 }
239 
240 bool belongs_to( Tree const& tree, TreeLink const& link )
241 {
242  return link.index() < tree.link_count() && &tree.link_at( link.index() ) == &link;
243 }
244 
245 bool belongs_to( TreeLink const& link, Tree const& tree )
246 {
247  return link.index() < tree.link_count() && &tree.link_at( link.index() ) == &link;
248 }
249 
250 bool belongs_to( Tree const& tree, Subtree const& subt )
251 {
252  return belongs_to( subt.link(), tree );
253 }
254 
255 bool belongs_to( Subtree const& subt, Tree const& tree )
256 {
257  return belongs_to( subt.link(), tree );
258 }
259 
261 {
262  // No need to check whether the two nodes belong to the same tree.
263  // If they don't, this loop will simply exit without success, so that a nullptr is returend.
264  for( auto it : node_links( lhs ) ) {
265  if( &it.link().outer().node() == &rhs ) {
266  return &it.link().edge();
267  }
268  }
269  return nullptr;
270 }
271 
272 TreeEdge const* edge_between( TreeNode const& lhs, TreeNode const& rhs )
273 {
274  // No need to check whether the two nodes belong to the same tree.
275  // If they don't, this loop will simply exit without success, so that a nullptr is returend.
276  for( auto it : node_links( lhs ) ) {
277  if( &it.link().outer().node() == &rhs ) {
278  return &it.link().edge();
279  }
280  }
281  return nullptr;
282 }
283 
284 // =================================================================================================
285 // Output Printing
286 // =================================================================================================
287 
288 std::string print_info( Tree const& tree )
289 {
290  return "<genesis::tree::Tree"
291  " node_count=" + std::to_string( tree.node_count() ) +
292  " edge_count=" + std::to_string( tree.edge_count() ) +
293  " link_count=" + std::to_string( tree.link_count() ) +
294  ">";
295 }
296 
297 std::string print_info( TreeEdge const& edge )
298 {
299  return "<genesis::tree::TreeEdge"
300  " index=" + std::to_string( edge.index() ) +
301  " has_data=" + ( edge.has_data() ? "true" : "false" ) +
302  ">";
303 }
304 
305 std::string print_info( TreeLink const& link )
306 {
307  return "<genesis::tree::TreeLink"
308  " index=" + std::to_string( link.index() ) +
309  // " has_data=" + ( edge.has_data() ? "true" : "false" ) +
310  ">";
311 }
312 
313 std::string print_info( TreeNode const& node )
314 {
315  return "<genesis::tree::TreeNode"
316  " index=" + std::to_string( node.index() ) +
317  " has_data=" + ( node.has_data() ? "true" : "false" ) +
318  ">";
319 }
320 
321 std::string print_gist( Tree const& tree, long items )
322 {
323  auto pc = PrinterCompact();
324  pc.limit( items );
325  return pc.print( tree );
326 }
327 
328 // =================================================================================================
329 // Validate
330 // =================================================================================================
331 
332 bool validate_topology( Tree const& tree )
333 {
334  // -----------------------------------------------------
335  // Empty Tree
336  // -----------------------------------------------------
337 
338  // check that the member arrays are valid: if at least one of them is empty, the tree is not
339  // fully initialized, so either it is a new tree without any data (all arrays empty, valid),
340  // or some are empty, but others not (not valid).
341  if (tree.links_.empty() || tree.nodes_.empty() || tree.edges_.empty()) {
342  bool empty = tree.links_.empty() && tree.nodes_.empty() && tree.edges_.empty();
343  if( !empty ) {
344  LOG_INFO << "Tree is not empty, but one of its data members is.";
345  }
346  return empty;
347  }
348 
349  // -----------------------------------------------------
350  // Links
351  // -----------------------------------------------------
352 
353  // Check Links.
354  std::vector<size_t> links_to_edges(tree.edges_.size(), 0);
355  std::vector<size_t> links_to_nodes(tree.nodes_.size(), 0);
356  for (size_t i = 0; i < tree.links_.size(); ++i) {
357  // Check indices.
358  if( i != tree.link_at(i).index() ) {
359  LOG_INFO << "Link at index " << i << " has wrong index ("
360  << tree.link_at(i).index() << ").";
361  return false;
362  }
363 
364  // Check next cycle and node.
365  auto nl = tree.links_[i].get();
366  do {
367  if( &nl->node() != &tree.links_[i]->node() ) {
368  LOG_INFO << "Link at index " << nl->index() << " points to wrong node.";
369  return false;
370  }
371  nl = &nl->next();
372  } while(nl != tree.links_[i].get());
373  ++links_to_nodes[tree.links_[i]->node().index()];
374 
375  // Check outer cycle.
376  if( &tree.links_[i]->outer().outer() != tree.links_[i].get() ) {
377  LOG_INFO << "Link at index " << i << " has wrong outer link.";
378  return false;
379  }
380 
381  // Check edge.
382  auto edge = &tree.links_[i]->edge();
383  if(
384  &edge->primary_link() != tree.links_[i].get() &&
385  &edge->secondary_link() != tree.links_[i].get()
386  ) {
387  LOG_INFO << "Link at index " << i << " has wrong edge pointer.";
388  return false;
389  }
390  ++links_to_edges[tree.links_[i]->edge().index()];
391  }
392 
393  // Check if all edges have been hit twice.
394  for (size_t i = 0; i < tree.edges_.size(); ++i) {
395  if (links_to_edges[i] != 2) {
396  LOG_INFO << "Edge at index " << i << " is not visited twice but " << links_to_edges[i]
397  << " times when traversing the links.";
398  return false;
399  }
400  }
401 
402  // Check if all nodes have been hit as many times as their degree is.
403  for (size_t i = 0; i < tree.nodes_.size(); ++i) {
404  if (links_to_nodes[i] != degree( *tree.nodes_[i] ) ) {
405  LOG_INFO << "Node at index " << i << " is not visited its degree ("
406  << degree( *tree.nodes_[i] )
407  << ") times, but " << links_to_nodes[i] << " times when "
408  << "traversing the links.";
409  return false;
410  }
411  }
412 
413  // -----------------------------------------------------
414  // Nodes
415  // -----------------------------------------------------
416 
417  // Check Nodes.
418  for (size_t i = 0; i < tree.nodes_.size(); ++i) {
419  // Check indices.
420  if( i != tree.node_at(i).index() ) {
421  LOG_INFO << "Node at index " << i << " has wrong index ("
422  << tree.node_at(i).index() << ").";
423  return false;
424  }
425 
426  // Check link.
427  if( &tree.nodes_[i]->link().node() != tree.nodes_[i].get() ) {
428  LOG_INFO << "Node at index " << i << " has wrong link.";
429  return false;
430  }
431 
432  // If a node claims to be the root, it better be the root.
433  if( is_root( tree.node_at(i) ) && i != tree.root_node().index() ) {
434  LOG_INFO << "Node at index " << i << " has is_root(), but it is not tree.root_node().";
435  return false;
436  }
437 
438  // Except for the root, all nodes must have a primary link that is the secondary link
439  // of its edge.
440  if( ! is_root( tree.node_at(i) ) &&
441  &tree.node_at(i).primary_link() != &tree.node_at(i).primary_link().edge().secondary_link()
442  ) {
443  LOG_INFO << "Node at " << i << " (not the root node) has a primary link which is not "
444  << "the secondary link of its edge.";
445  return false;
446  }
447 
448  // All (primary) links must point towards the root.
449  size_t root_c = 0;
450  auto root_l = &( tree.node_at(i).primary_link() );
451  while( root_l != &( tree.root_node().link() )) {
452  root_l = &( root_l->outer().node().primary_link() );
453  ++root_c;
454 
455  // We need to avoid infinite loops in case of wrong trees, so that this function
456  // correctly termines. We cannot need more hops than nodes in the tree!
457  if( root_c > tree.node_count() ) {
458  LOG_INFO << "Node at " << i << " and the nodes towards the root contain "
459  << "a primary link which is not pointing towards the root.";
460  return false;
461  }
462  }
463  }
464 
465  // -----------------------------------------------------
466  // Edges
467  // -----------------------------------------------------
468 
469  // Check Edges.
470  for (size_t i = 0; i < tree.edges_.size(); ++i) {
471  // Check indices.
472  if( i != tree.edge_at(i).index() ) {
473  LOG_INFO << "Edge at index " << i << " has wrong index ("
474  << tree.edge_at(i).index() << ").";
475  return false;
476  }
477 
478  // Check links.
479  if( &tree.edges_[i]->primary_link().edge() != tree.edges_[i].get() ) {
480  LOG_INFO << "Edge at index " << i << " has wrong primary link.";
481  return false;
482  }
483  if( &tree.edges_[i]->secondary_link().edge() != tree.edges_[i].get() ) {
484  LOG_INFO << "Edge at index " << i << " has wrong secondary link.";
485  return false;
486  }
487 
488  // Check outer links.
489  if( &tree.edges_[i]->primary_link().outer() != &tree.edges_[i]->secondary_link() ) {
490  LOG_INFO << "Edge at index " << i << " has a primary link that does not "
491  << "connect to its secondary link.";
492  return false;
493  }
494  if( &tree.edges_[i]->secondary_link().outer() != &tree.edges_[i]->primary_link() ) {
495  LOG_INFO << "Edge at index " << i << " has a secondary link that does not "
496  << "connect to its primary link.";
497  return false;
498  }
499 
500  // Check primary node, except for root.
501  if( ! is_root( tree.edge_at(i).primary_node() ) &&
502  &tree.edge_at(i).primary_node().primary_link() == &tree.edge_at(i).primary_link()
503  ) {
504  LOG_INFO << "Edge at " << i << " has a primary node that does not "
505  << "point towards the root.";
506  return false;
507  }
508 
509  // Check secondary node.
510  if( &tree.edge_at(i).secondary_node().primary_link() != &tree.edge_at(i).secondary_link() ) {
511  LOG_INFO << "Edge at " << i << " has a secondary node that does not "
512  << "point towards the root.";
513  return false;
514  }
515 
516  // All primary links must point towards the root.
517  size_t root_c = 0;
518  auto root_l = &( tree.edge_at(i).primary_link() );
519  while( root_l != &( tree.root_node().link() )) {
520  root_l = &( root_l->node().primary_link().edge().primary_link() );
521  ++root_c;
522 
523  // We need to avoid infinite loops in case of wrong trees, so that this function
524  // correctly termines. We cannot need more hops than nodes in the tree!
525  if( root_c > tree.node_count() ) {
526  LOG_INFO << "Edge at " << i << " and the nodes towards the root contain "
527  << "a primary link which is not pointing towards the root.";
528  return false;
529  }
530  }
531  }
532 
533  // -----------------------------------------------------
534  // Eulertour
535  // -----------------------------------------------------
536 
537  // If we are here, all three arrays (links, nodes, edges) contain data, so we can start a full
538  // traversal along all links.
539 
540  // Count, how many times the elements are hit while traversing.
541  std::vector<size_t> it_links(tree.links_.size(), 0);
542  std::vector<size_t> it_edges(tree.edges_.size(), 0);
543  std::vector<size_t> it_nodes(tree.nodes_.size(), 0);
544 
545  // Do the traversal. We do not use the iterator here, to keep it simple when testing.
546  // (We want to validate the tree here, not the iterator.)
547  auto link = tree.links_.front().get();
548  do {
549  ++it_links[ link->index() ];
550  ++it_edges[ link->edge().index() ];
551  ++it_nodes[ link->node().index() ];
552  link = &link->next().outer();
553 
554  // Check if we have a loop. Baaad.
555  if( it_links[ link->index() ] > 1 ) {
556  LOG_INFO << "Loop or other kind of wrong link chain in Tree.";
557  return false;
558  }
559  } while (link != tree.links_.front().get());
560 
561  // Check if all links have been hit once.
562  for (size_t i = 0; i < tree.links_.size(); i++) {
563  if (it_links[i] != 1) {
564  LOG_INFO << "Link at index " << i << " is not visited 1 but " << it_links[i]
565  << " times when iterating the tree.";
566  return false;
567  }
568  }
569 
570  // Check if all edges have been hit twice.
571  for (size_t i = 0; i < tree.edges_.size(); ++i) {
572  if (it_edges[i] != 2) {
573  LOG_INFO << "Edge at index " << i << " is not visited 2 but " << it_edges[i]
574  << " times when iterating the tree.";
575  return false;
576  }
577  }
578 
579  // Check if all nodes have been hit as many times as their degree is.
580  for (size_t i = 0; i < tree.nodes_.size(); ++i) {
581  if (it_nodes[i] != degree( *tree.nodes_[i] ) ) {
582  LOG_INFO << "Node at index " << i << " is not visited "
583  << degree( *tree.nodes_[i] )
584  << " times, but " << it_nodes[i] << " times when iterating the "
585  << "tree.";
586  return false;
587  }
588  }
589 
590  // -----------------------------------------------------
591  // Root
592  // -----------------------------------------------------
593 
594  // All edges of the root node need to have this node as their primary node.
595  auto rl = &( tree.root_link().next());
596  while( rl != &( tree.root_link()) ) {
597  if( &( rl->edge().primary_link() ) != rl ) {
598  LOG_INFO << "Root node of the tree is not root in the topology.";
599  return false;
600  }
601  rl = &( rl->next() );
602  }
603 
604  // Check root link and node.
605  if( &tree.root_link() != &tree.root_link().node().primary_link() ) {
606  LOG_INFO << "Tree root link is not the primary link of its node.";
607  return false;
608  }
609 
610  // Further check the root.
611  if( ! is_root( tree.root_node() ) ) {
612  LOG_INFO << "Root node is not true in is_root().";
613  return false;
614  }
615 
616  return true;
617 }
618 
619 } // namespace tree
620 } // namespace genesis
LOG_INFO
#define LOG_INFO
Log an info message. See genesis::utils::LoggingLevel.
Definition: logging.hpp:100
genesis::tree::TreeEdge::primary_link
TreeLink & primary_link()
Return the TreeLink of this TreeEdge that points towards the root.
Definition: edge.hpp:114
genesis::tree::convert
Tree convert(Tree const &source, std::function< std::unique_ptr< BaseNodeData >(BaseNodeData const &node_data)> node_data_converter, std::function< std::unique_ptr< BaseEdgeData >(BaseEdgeData const &edge_data)> edge_data_converter)
Create a tree with the same topology as the source tree, while converting its data.
Definition: tree/function/operators.cpp:53
genesis::tree::Subtree::link
TreeLink const & link() const
Get the TreeLink that separates the subtree from the rest of the tree.
Definition: subtree.hpp:125
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::PrinterCompact
Print a Tree in a compact form, i.e., each node and edge on one line.
Definition: compact.hpp:82
genesis::tree::print_gist
std::string print_gist(Tree const &tree, long items)
Definition: tree/function/operators.cpp:321
genesis::tree::print_info
std::string print_info(Tree const &tree)
Definition: tree/function/operators.cpp:288
genesis::tree::TreeEdge::index
size_t index() const
Return the index of this Edge.
Definition: edge.hpp:106
genesis::tree::BaseEdgeData
Base class for storing data on Edges of a Tree.
Definition: edge_data.hpp:66
functions.hpp
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
genesis::tree::preorder
utils::Range< IteratorPreorder< true > > preorder(ElementType const &element)
Definition: tree/iterator/preorder.hpp:264
genesis::tree::belongs_to
bool belongs_to(Tree const &tree, TreeNode const &node)
Return whether the TreeNode belongs to the Tree, i.e., whether it is owned by the Tree.
Definition: tree/function/operators.cpp:220
genesis::tree::node_links
utils::Range< IteratorNodeLinks< true > > node_links(ElementType const &element)
Definition: node_links.hpp:186
genesis::tree::degree
size_t degree(TreeLink const &link)
Return the degree of the node for a given TreeLink, i.e. how many neighbouring nodes it has.
Definition: tree/function/functions.cpp:103
genesis::tree::Tree::root_node
TreeNode & root_node()
Return the TreeNode at the current root of the Tree.
Definition: tree/tree.hpp:300
genesis::tree::identical_topology
bool identical_topology(Tree const &lhs, Tree const &rhs, bool identical_indices)
Return whether both trees have an identical topology.
Definition: tree/function/operators.cpp:169
genesis::tree::equal
bool equal(Tree const &lhs, Tree const &rhs, std::function< bool(TreeNode const &, TreeNode const &) > node_comparator, std::function< bool(TreeEdge const &, TreeEdge const &) > edge_comparator)
Compare two trees for equality given binary comparator functionals for their nodes and edges.
Definition: tree/function/operators.cpp:80
genesis::tree::TreeEdge::secondary_node
TreeNode & secondary_node()
Return the TreeNode of this TreeEdge that points away from the root.
Definition: edge.hpp:162
genesis::population::to_string
std::string to_string(GenomeLocus const &locus)
Definition: function/genome_locus.hpp:52
genesis::tree::TreeNode::primary_link
TreeLink & primary_link()
Return the TreeLink that points towards the root.
Definition: tree/tree/node.hpp:110
genesis::tree::edge_between
TreeEdge * edge_between(TreeNode &lhs, TreeNode &rhs)
Return the TreeEdge between two TreeNode&s, if they are neighbours, or nullptr otherwise.
Definition: tree/function/operators.cpp:260
genesis::tree::Tree
Class for representing phylogenetic trees.
Definition: tree/tree.hpp:97
compact.hpp
subtree.hpp
logging.hpp
Provides easy and fast logging functionality.
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::is_root
bool is_root(TreeLink const &link)
Return whether the link belongs to the root node of its Tree.
Definition: tree/function/functions.cpp:89
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::Subtree
Reference to a subtree of a Tree.
Definition: subtree.hpp:69
genesis::tree::TreeEdge
Definition: edge.hpp:60
genesis::tree::TreeNode
Definition: tree/tree/node.hpp:58
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::TreeNode::link
TreeLink & link()
Return the TreeLink that points towards the root.
Definition: tree/tree/node.hpp:129
genesis::tree::BaseNodeData
Base class for storing data on Nodes of a Tree.
Definition: node_data.hpp:66
genesis::tree::TreeEdge::primary_node
TreeNode & primary_node()
Return the TreeNode of this TreeEdge that points towards the root.
Definition: edge.hpp:146
operators.hpp
Tree operator functions.
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::Tree::link_at
TreeLink & link_at(size_t index)
Return the TreeLink at a certain index.
Definition: tree/tree.hpp:202
genesis::tree::TreeNode::index
size_t index() const
Return the index of this Node.
Definition: tree/tree/node.hpp:102
genesis::tree::TreeNode::data_ptr
BaseNodeData * data_ptr()
Return a pointer to the data.
Definition: tree/tree/node.hpp:232
genesis::tree::validate_topology
bool validate_topology(Tree const &tree)
Validate that all internal pointers of the Tree elements (TreeLinks, TreeNodes, TreeEdges) to each ot...
Definition: tree/function/operators.cpp:332
genesis::tree::TreeEdge::secondary_link
TreeLink & secondary_link()
Return the TreeLink of this TreeEdge that points away from the root.
Definition: edge.hpp:130
preorder.hpp
genesis::tree::Tree::edge_count
size_t edge_count() const
Return the number of TreeEdges of the Tree.
Definition: tree/tree.hpp:272