ARB
arb_consensus_tree.cxx
Go to the documentation of this file.
1 // ============================================================= //
2 // //
3 // File : arb_consensus_tree.cxx //
4 // Purpose : build consensus tree with the same library //
5 // as ARB-NJ //
6 // //
7 // Coded by Ralf Westram (coder@reallysoft.de) in March 2012 //
8 // Institute of Microbiology (Technical University Munich) //
9 // http://www.arb-home.de/ //
10 // //
11 // ============================================================= //
12 
13 #include <CT_ctree.hxx>
14 #include <TreeRead.h>
15 #include <TreeWrite.h>
16 #include <arb_str.h>
17 #include <arb_diff.h>
18 #include <arb_defs.h>
19 
20 using namespace std;
21 
22 static TreeNode *build_consensus_tree(const CharPtrArray& input_trees, GB_ERROR& error, size_t& different_species, double weight, char *&comment) {
23  // read all input trees, generate and return consensus tree
24  // (Note: the 'weight' used here doesn't matter atm, since all trees are added with the same weight)
25 
26  arb_assert(!error);
27  error = NULp;
28  comment = NULp;
29 
30  TreeNode *consense_tree = NULp;
31  if (input_trees.empty()) {
32  error = "no trees given";
33  }
34  else {
35  ConsensusTreeBuilder tree_builder;
36 
37  for (size_t i = 0; !error && i<input_trees.size(); ++i) {
38  char *warnings = NULp;
39 
40  TreeRoot *root = new SizeAwareRoot; // will be deleted when tree gets deleted
41  SizeAwareTree *tree = DOWNCAST(SizeAwareTree*, TREE_load(input_trees[i], root, NULp, true, &warnings));
42  if (!tree) {
43  error = GBS_global_string("Failed to load tree '%s' (Reason: %s)", input_trees[i], GB_await_error());
44  }
45  else {
46  if (warnings) {
47  GB_warningf("while loading tree '%s':\n%s", input_trees[i], warnings);
48  free(warnings);
49  }
50  tree_builder.add(tree, input_trees[i], weight);
51  }
52  }
53 
54  if (!error) consense_tree = tree_builder.get(different_species, error);
55  if (!error) comment = tree_builder.get_tree_remark();
56  }
57  arb_assert(contradicted(consense_tree, error));
58  return consense_tree;
59 }
60 
61 static char *create_tree_name(const char *savename) {
62  // create a DB treename (using savename as hint)
63  char *tree_name;
64  {
65  // as default use part behind '/' and remove file extension
66  const char *lslash = strrchr(savename, '/');
67  if (lslash) savename = lslash+1;
68 
69  const char *ldot = strrchr(savename, '.');
70 
71  tree_name = ldot ? ARB_strpartdup(savename, ldot-1) : ARB_strdup(savename);
72  if (tree_name[0] == 0) freedup(tree_name, "tree_consensus");
73  }
74 
75  // make sure tree name starts with 'tree_'
76  if (!ARB_strBeginsWith(tree_name, "tree_")) {
77  freeset(tree_name, GBS_global_string_copy("tree_%s", tree_name));
78  }
79  return tree_name;
80 }
81 
82 static GB_ERROR save_tree_as_newick(TreeNode *tree, const char *savename, const char *comment) {
83  // save a tree to a newick file
84 
85  // since ARB only saves trees out of a database,
86  // i use a hack here:
87  // - create temp DB
88  // - save tree there
89  // - save to newick as usual
90 
91  GB_shell shell;
92  GBDATA *gb_main = GB_open("", "crw");
94 
95  if (!gb_main) {
96  error = GB_await_error();
97  }
98  else {
99  char *db_tree_name = create_tree_name(savename);
100 
101  {
102  GB_transaction ta(gb_main);
103  error = GBT_write_tree_with_remark(gb_main, db_tree_name, tree, comment);
104  }
105  if (!error) error = TREE_write_Newick(gb_main, db_tree_name, NULp, true, true, true, true, TREE_SINGLE_QUOTES, savename);
106 
107  free(db_tree_name);
108  GB_close(gb_main);
109  }
110 
111  if (error) {
112  error = GBS_global_string("Failed to save tree to '%s' (Reason: %s)", savename, error);
113  }
114 
115  return error;
116 }
117 
118 int ARB_main(int argc, char *argv[]) {
119  GB_ERROR error = NULp;
120 
121  if (argc<2) {
122  printf("Usage: arb_consensus_tree [options] [tree]+\n"
123  "Purpose: Create a consensus tree out of multiple trees\n"
124  " options:\n"
125  " -w outfile write consensus tree to outfile\n");
126 
127  // @@@ wanted options
128  // - do not add relative frequency of used subtrees as bootstrap values
129  // - multifurcate branches with bootstrap value below XXX
130  // - eliminate branches with bootstrap value below YYY
131  // - ... ?
132  }
133  else {
134  char *savename = NULp;
135 
136  ConstStrArray input_tree_names;
137 
138  for (int a = 1; a<argc; ++a) {
139  const char *arg = argv[a];
140  if (arg[0] == '-') {
141  switch (arg[1]) {
142  case 'w': savename = ARB_strdup(argv[++a]); break;
143  default : error = GBS_global_string("Unknown switch '-%c'", arg[1]); break;
144  }
145  }
146  else {
147  input_tree_names.put(argv[a]);
148  }
149  }
150 
151  if (!error && input_tree_names.empty()) error = "no input trees specified";
152 
153  if (!error) {
154  size_t species_count;
155  char *comment;
156  TreeNode *cons_tree = build_consensus_tree(input_tree_names, error, species_count, 1.0, comment);
157 
158  if (!cons_tree) {
159  error = GBS_global_string("Failed to build consensus tree (Reason: %s)", error);
160  }
161  else {
162  size_t leafs = GBT_count_leafs(cons_tree);
163  double percent = size_t((leafs*1000)/species_count)/10.0;
164 
165  printf("Generated tree contains %.1f%% of species (%zu of %zu found in input trees)\n",
166  percent, leafs, species_count);
167 
168  if (savename) {
169  error = save_tree_as_newick(cons_tree, savename, comment);
170  }
171  else {
172  printf("successfully created consensus tree\n"
173  "(no savename specified -> tree not saved)\n");
174  }
175  UNCOVERED();
176  destroy(cons_tree);
177  }
178  free(comment);
179  }
180  free(savename);
181  }
182 
183  if (error) {
184  printf("Error in arb_consensus_tree: %s\n", error);
185  }
186 
187  return error ? EXIT_FAILURE : EXIT_SUCCESS;
188 }
189 
190 // --------------------------------------------------------------------------------
191 
192 #ifdef UNIT_TESTS
193 #ifndef TEST_UNIT_H
194 #include <test_unit.h>
195 #endif
196 
197 #include "command_output.h"
198 
199 // #define TEST_AUTO_UPDATE // uncomment to update expected trees (if more than date differs)
200 
201 static char *custom_tree_name(int dir, const char *name) { return GBS_global_string_copy("consense/%i/%s.tree", dir, name); }
202 static char *custom_numbered_tree_name(int dir, const char *name, int treeNr) { return GBS_global_string_copy("consense/%i/%s_%i.tree", dir, name, treeNr); }
203 
204 static void add_inputnames(StrArray& to, int dir, const char *basename, int first_tree, int last_tree) {
205  for (int t = first_tree; t <= last_tree; ++t) {
206  to.put(custom_numbered_tree_name(dir, basename, t));
207  }
208 }
209 
210 static double calc_intree_distance(TreeNode *tree) {
211  if (tree->is_leaf()) return 0.0;
212  return
213  tree->leftlen +
214  tree->rightlen +
215  calc_intree_distance(tree->get_leftson()) +
216  calc_intree_distance(tree->get_rightson());
217 }
218 
219 #define LENSUM_EPSILON .000001
220 
221 static arb_test::match_expectation consense_tree_generated(TreeNode *tree, GB_ERROR error, size_t species_count, size_t expected_species_count, double expected_intree_distance) {
222  using namespace arb_test;
223  expectation_group expected;
224 
225  expected.add(that(error).is_equal_to_NULL());
226  expected.add(that(tree).does_differ_from_NULL());
227 
228  if (tree) {
229  expected.add(that(species_count).is_equal_to(expected_species_count));
230  expected.add(that(GBT_count_leafs(tree)).is_equal_to(expected_species_count));
231  expected.add(that(calc_intree_distance(tree)).fulfills(epsilon_similar(LENSUM_EPSILON), expected_intree_distance));
232  }
233 
234  return all().ofgroup(expected);
235 }
236 
237 static arb_test::match_expectation build_expected_consensus_tree(const int treedir, const char *basename, int first_tree, int last_tree, double weight, const char *outbasename, size_t expected_species_count, double expected_intree_distance) {
238  using namespace arb_test;
239  expectation_group expected;
240  arb_suppress_progress hideProgress;
241 
242  GB_ERROR error = NULp;
243  StrArray input_tree_names;
244  add_inputnames(input_tree_names, treedir, basename, first_tree, last_tree);
245 
246  size_t species_count;
247  char *comment;
248  TreeNode *tree = build_consensus_tree(input_tree_names, error, species_count, weight, comment);
249  expected.add(consense_tree_generated(tree, error, species_count, expected_species_count, expected_intree_distance));
250 
251  char *saveas = custom_tree_name(treedir, outbasename);
252  error = save_tree_as_newick(tree, saveas, comment);
253  expected.add(that(error).is_equal_to_NULL());
254 
255  if (!error) {
256  char *expected_save = custom_tree_name(treedir, GBS_global_string("%s_expected", outbasename));
257  bool exported_as_expected = arb_test::textfiles_have_difflines_ignoreDates(expected_save, saveas, 0);
258 
259 #if defined(TEST_AUTO_UPDATE)
260  if (!exported_as_expected) {
261  TEST_COPY_FILE(saveas, expected_save);
262  }
263 #else // !defined(TEST_AUTO_UPDATE)
264  expected.add(that(exported_as_expected).is_equal_to(true));
265 #endif
267  free(expected_save);
268  }
269 
270  free(saveas);
271  free(comment);
272  destroy(tree);
273 
274  return all().ofgroup(expected);
275 }
276 
277 void TEST_consensus_tree_1() {
278  TEST_EXPECTATION(build_expected_consensus_tree(1, "bootstrapped", 1, 5, 0.7, "consense1", 22, 0.925779));
279  // ../UNIT_TESTER/run/consense/1/consense1.tree
280 }
281 void TEST_consensus_tree_1_single() {
282  TEST_EXPECTATION(build_expected_consensus_tree(1, "bootstrapped", 1, 1, 0.01, "consense1_single", 22, 0.924610));
283  // ../UNIT_TESTER/run/consense/1/consense1_single.tree
284 }
285 
286 void TEST_consensus_tree_2() {
287  TEST_EXPECTATION(build_expected_consensus_tree(2, "bootstrapped", 1, 4, 2.5, "consense2", 59, 2.849827));
288  // ../UNIT_TESTER/run/consense/2/consense2.tree
289 }
290 
291 void TEST_consensus_tree_3() {
292  TEST_EXPECTATION(build_expected_consensus_tree(3, "bootstrapped", 1, 3, 137.772, "consense3", 128, 2.170685));
293  // ../UNIT_TESTER/run/consense/3/consense3.tree
294 }
295 
296 void TEST_consensus_tree_from_disjunct_trees() {
297  TEST_EXPECTATION(build_expected_consensus_tree(4, "disjunct", 1, 2, 137.772, "disjunct_merged", 15, 2.034290));
298  // ../UNIT_TESTER/run/consense/4/disjunct_merged.tree
299 }
300 
301 void TEST_consensus_tree_from_partly_overlapping_trees() {
302  // tree_disjunct_3 contains 7 species
303  // (3 from upper subtree (tree_disjunct_1) and 4 from lower subtree (tree_disjunct_2))
304 
305  TEST_EXPECTATION(build_expected_consensus_tree(4, "disjunct", 1, 3, 137.772, "overlap_merged", 15, 2.596455));
306  // ../UNIT_TESTER/run/consense/4/overlap_merged.tree
307 }
308 
309 void TEST_consensus_tree_from_minimal_overlapping_trees() {
310  // tree_disjunct_0 only contains 2 species (1 from upper and 1 from lower subtree).
311  TEST_EXPECTATION(build_expected_consensus_tree(4, "disjunct", 0, 2, 137.772, "overlap_mini_merged", 15, 2.750745));
312  // ../UNIT_TESTER/run/consense/4/overlap_mini_merged.tree
313 }
314 
315 void TEST_consensus_tree_described_in_arbhelp() {
316  // see ../HELP_SOURCE/oldhelp/consense_algo.hlp
317  TEST_EXPECTATION(build_expected_consensus_tree(5, "help", 1, 2, 2.0, "help_merged", 6, 1.050000));
318  // ../UNIT_TESTER/run/consense/5/help_merged.tree
319 }
320 
321 void TEST_consensus_tree_from_trees_overlapping_by_twothirds() {
322  // These 3 trees where copied from an existing tree.
323  // From each copy one third of all species has been removed
324  // (removed sets were disjunct)
325  TEST_EXPECTATION(build_expected_consensus_tree(6, "overlap_two_thirds", 1, 3, 19.2, "overlap_twothirds_merged", 15, 3.561680));
326  // ../UNIT_TESTER/run/consense/6/overlap_twothirds_merged.tree
327 }
328 
329 void TEST_consensus_tree_from_mostly_overlapping_trees() {
330  // the 3 trees were copied from tree_disjunct_source.
331  // from each tree 2 (different) species were deleted.
332  TEST_EXPECTATION(build_expected_consensus_tree(7, "disjunct_del2", 1, 3, 137.772, "overlap_mostly", 15, 1.820057));
333  // ../UNIT_TESTER/run/consense/7/overlap_mostly.tree
334 }
335 
336 void TEST_consensus_tree_from_mostly_overlapping_trees_2() {
337  // the 3 trees were copied from tree_disjunct1
338  // from each tree 1 (different) species was deleted.
339  TEST_EXPECTATION(build_expected_consensus_tree(8, "overlap2", 1, 3, 137.772, "overlap2_mostly", 8, 0.529109));
340  // ../UNIT_TESTER/run/consense/8/overlap2_mostly.tree
341 }
342 TEST_PUBLISH(TEST_consensus_tree_from_mostly_overlapping_trees_2);
343 
344 
345 #define REPEATED_TESTS
346 
347 #if defined(REPEATED_TESTS)
348 void TEST_consensus_tree_generation_is_deterministic() {
349  TEST_consensus_tree_described_in_arbhelp();
350  TEST_consensus_tree_from_minimal_overlapping_trees();
351  TEST_consensus_tree_from_partly_overlapping_trees();
352  TEST_consensus_tree_from_disjunct_trees();
353  TEST_consensus_tree_3();
354  TEST_consensus_tree_2();
355  TEST_consensus_tree_1_single();
356  TEST_consensus_tree_1();
357 }
358 
359 void TEST_arb_consensus_tree() {
360  TEST_STDOUT_CONTAINS("(arb_consensus_tree -x || true)", "Unknown switch '-x'");
361  TEST_STDOUT_CONTAINS("(arb_consensus_tree -w sth || true)", "no input trees specified");
362 
363  {
364  char *saveas = custom_tree_name(1, "consense1");
365  char *expected = custom_tree_name(1, "consense1_expected");
366 
367  TEST_OUTPUT_CONTAINS("arb_consensus_tree"
368  " -w consense/1/consense1.tree"
369  " consense/1/bootstrapped_1.tree"
370  " consense/1/bootstrapped_2.tree"
371  " consense/1/bootstrapped_3.tree"
372  " consense/1/bootstrapped_4.tree"
373  " consense/1/bootstrapped_5.tree",
374  (const char *)NULp,
375  "Created new database \"\"");
376 
377  TEST_EXPECT_TEXTFILE_DIFFLINES_IGNORE_DATES(saveas, expected, 0);
379 
380  free(expected);
381  free(saveas);
382  }
383 
384  {
385  char *saveas = custom_tree_name(2, "consense2");
386  char *expected = custom_tree_name(2, "consense2_expected");
387 
388  TEST_OUTPUT_CONTAINS("arb_consensus_tree"
389  " -w consense/2/consense2.tree"
390  " consense/2/bootstrapped_1.tree"
391  " consense/2/bootstrapped_2.tree"
392  " consense/2/bootstrapped_3.tree"
393  " consense/2/bootstrapped_4.tree",
394  (const char *)NULp,
395  "Created new database \"\"");
396 
397  TEST_EXPECT_TEXTFILE_DIFFLINES_IGNORE_DATES(saveas, expected, 0);
399 
400  free(expected);
401  free(saveas);
402  }
403 }
404 #endif // REPEATED_TESTS
405 
406 // #define TREEIO_AUTO_UPDATE // uncomment to auto-update expected test-results
407 // #define TREEIO_AUTO_UPDATE_IF_EXPORT_DIFFERS // uncomment to auto-update expected test-results
408 // #define TREEIO_AUTO_UPDATE_IF_REEXPORT_DIFFERS // uncomment to auto-update expected test-results
409 
410 static const char *findFirstNameContaining(TreeNode *tree, const char *part) {
411  const char *found = NULp;
412  if (tree->name && strstr(tree->name, part)) {
413  found = tree->name;
414  }
415  else if (!tree->is_leaf()) {
416  found = findFirstNameContaining(tree->get_leftson(), part);
417  if (!found) found = findFirstNameContaining(tree->get_rightson(), part);
418  }
419  return found;
420 }
421 
422 void TEST_SLOW_treeIO_stable() {
423  const char *dbname = "trees/bootstrap_groups.arb";
424  const char *treename = "tree_bootstrap_and_groups";
425  const char *savename = "bg";
426 
427  GB_shell shell;
428  GBDATA *gb_main = GB_open(dbname, "rw");
429 
430  TEST_REJECT_NULL(gb_main);
431 
432  char *outfile = GBS_global_string_copy("trees/%s.tree", savename);
433 
434  for (int save_branchlengths = 0; save_branchlengths <= 1; ++save_branchlengths) {
435  for (int save_bootstraps = 0; save_bootstraps <= 1; ++save_bootstraps) {
436  for (int save_groupnames = 0; save_groupnames <= 1; ++save_groupnames) {
437  bool quoting_occurs = save_bootstraps && save_groupnames;
438  for (int pretty = 0; pretty <= 1; ++pretty) {
439 
440  for (int quoting = TREE_DISALLOW_QUOTES; quoting <= (quoting_occurs ? TREE_DOUBLE_QUOTES : TREE_DISALLOW_QUOTES); ++quoting) {
441  TREE_node_quoting quoteMode = TREE_node_quoting(quoting);
442 
443  char *paramID = GBS_global_string_copy("%s_%s%s%s_%i",
444  pretty ? "p" : "s",
445  save_bootstraps ? "Bs" : "",
446  save_groupnames ? "Grp" : "",
447  save_branchlengths ? "Len" : "",
448  quoteMode);
449 
450  TEST_ANNOTATE(GBS_global_string("for paramID='%s'", paramID));
451 
452  GB_ERROR export_error = TREE_write_Newick(gb_main, treename, NULp, save_branchlengths, save_bootstraps, save_groupnames, pretty, quoteMode, outfile);
453  TEST_EXPECT_NULL(export_error);
454 
455  char *expectedfile = GBS_global_string_copy("trees/%s_exp_%s.tree", savename, paramID);
456 
457 #if defined(TREEIO_AUTO_UPDATE)
458  system(GBS_global_string("cp %s %s", outfile, expectedfile));
459 #else // !defined(TREEIO_AUTO_UPDATE)
460  bool exported_as_expected = arb_test::textfiles_have_difflines_ignoreDates(expectedfile, outfile, 0);
461 #if defined(TREEIO_AUTO_UPDATE_IF_EXPORT_DIFFERS)
462  if (!exported_as_expected) {
463  system(GBS_global_string("cp %s %s", outfile, expectedfile));
464  }
465 #else // !defined(TREEIO_AUTO_UPDATE_IF_EXPORT_DIFFERS)
466  TEST_EXPECT(exported_as_expected);
467 #endif
468 
469  // reimport exported tree
470  const char *reloaded_treename = "tree_reloaded";
471  {
472  char *comment = NULp;
473  TreeNode *tree = TREE_load(expectedfile, new SimpleRoot, &comment, true, NULp);
474  GB_ERROR load_error = tree ? NULp : GB_await_error();
475 
477  that(load_error).is_equal_to_NULL()));
478  // store tree in DB
479  {
480  GB_transaction ta(gb_main);
481  GB_ERROR store_error = GBT_write_tree_with_remark(gb_main, reloaded_treename, tree, comment);
482  TEST_EXPECT_NULL(store_error);
483  }
484  free(comment);
485 
486  if (save_groupnames) {
487  const char *quotedGroup = findFirstNameContaining(tree, "quoted");
488  const char *underscoreGroup = findFirstNameContaining(tree, "bs100");
489  TEST_EXPECT_EQUAL(quotedGroup, "quoted");
490  TEST_EXPECT_EQUAL(underscoreGroup, "__bs100");
491  }
492  const char *capsLeaf = findFirstNameContaining(tree, "Caps");
493  TEST_EXPECT_EQUAL(capsLeaf, "_MhuCaps");
494 
495  destroy(tree);
496  }
497 
498  // export again
499  GB_ERROR reexport_error = TREE_write_Newick(gb_main, reloaded_treename, NULp, save_branchlengths, save_bootstraps, save_groupnames, pretty, quoteMode, outfile);
500  TEST_EXPECT_NULL(reexport_error);
501 
502  // eliminate comments added by loading/saving
503  char *outfile2 = GBS_global_string_copy("trees/%s2.tree", savename);
504  {
505  char *cmd = GBS_global_string_copy("cat %s"
506  " | grep -v 'Loaded from trees/.*_exp_'"
507  " | grep -v 'tree_reloaded saved to'"
508  " > %s", outfile, outfile2);
510  free(cmd);
511  }
512 
513  bool reexported_as_expected = arb_test::textfiles_have_difflines(expectedfile, outfile2, 0);
514 
515 #if defined(TREEIO_AUTO_UPDATE_IF_REEXPORT_DIFFERS)
516  if (!reexported_as_expected) {
517  system(GBS_global_string("cp %s %s", outfile2, expectedfile));
518  }
519 #else // !defined(TREEIO_AUTO_UPDATE_IF_REEXPORT_DIFFERS)
520  TEST_EXPECT(reexported_as_expected);
521 #endif
522 
523  TEST_EXPECT_ZERO_OR_SHOW_ERRNO(unlink(outfile2));
524  free(outfile2);
525 #endif
526  free(expectedfile);
527  free(paramID);
528  }
529  }
530  }
531  }
532  }
533  TEST_ANNOTATE(NULp);
534 
535  TEST_EXPECT_ZERO_OR_SHOW_ERRNO(unlink(outfile));
536  free(outfile);
537 
538  GB_close(gb_main);
539 }
540 
541 void TEST_CONSENSUS_TREE_functionality() {
542  // functionality wanted in TreeNode (for use in library CONSENSUS_TREE)
543 
544  char *comment = NULp;
545 
546  SizeAwareTree *tree = DOWNCAST(SizeAwareTree*, TREE_load("trees/bg_exp_p_GrpLen_0.tree",
547  new SizeAwareRoot,
548  &comment, false, NULp));
549  // -> ../UNIT_TESTER/run/trees/bg_exp_p_GrpLen_0.tree
550 
551 #define ORG_1111 "(AticSea6,(RblAerol,RblMesop))"
552 #define TOP_1111 "((RblAerol,RblMesop),AticSea6)"
553 #define BOT_1111 ORG_1111
554 
555 #define ORG_11121 "((DnrShiba,RsbElon4),MmbAlkal)"
556 #define TOP_11121 ORG_11121
557 #define BOT_11121 "(MmbAlkal,(DnrShiba,RsbElon4))"
558 
559 #define ORG_11122 "((MabPelag,MabSalin),PaoMaris)"
560 #define TOP_11122 ORG_11122
561 #define BOT_11122 "(PaoMaris,(MabPelag,MabSalin))"
562 
563 #define ORG_1112 "(" ORG_11121 "," ORG_11122 ")"
564 #define TOP_1112 "(" TOP_11121 "," TOP_11122 ")"
565 #define BOT_1112 "(" BOT_11121 "," BOT_11122 ")"
566 #define EDG_1112 "(" TOP_11121 "," BOT_11122 ")"
567 
568 #define ORG_111 "(" ORG_1111 "," ORG_1112 ")"
569 #define TOP_111 "(" TOP_1112 "," TOP_1111 ")"
570 #define BOT_111 "(" BOT_1111 "," BOT_1112 ")"
571 #define EDG_111 "(" EDG_1112 "," BOT_1111 ")"
572 
573 #define ORG_112 "(OnlGran2,RsnAnta2)"
574 #define TOP_112 ORG_112
575 #define BOT_112 ORG_112
576 
577 #define ORG_11 "(" ORG_111 "," ORG_112 ")"
578 #define TOP_11 "(" TOP_111 "," TOP_112 ")"
579 #define BOT_11 "(" BOT_112 "," BOT_111 ")"
580 #define EDG_11 "(" EDG_111 "," BOT_112 ")"
581 
582 #define ORG_12 "(_MhuCaps,ThtNivea)"
583 #define TOP_12 "(ThtNivea,_MhuCaps)"
584 #define BOT_12 TOP_12
585 
586 #define ORG_1 "(" ORG_11 "," ORG_12 ")"
587 #define TOP_1 "(" TOP_11 "," TOP_12 ")"
588 #define BOT_1 "(" BOT_12 "," BOT_11 ")"
589 #define EDG_1 "(" EDG_11 "," BOT_12 ")"
590 
591 #define ORG_2 "((LbnMarin,LbnzAlb4),LbnAlexa)"
592 #define TOP_2 ORG_2
593 #define BOT_2 "(LbnAlexa,(LbnMarin,LbnzAlb4))"
594 
595  // test swap_sons
597  TEST_EXPECT_NEWICK(nSIMPLE, tree, "(" ORG_1 "," ORG_2 ");");
598  tree->swap_sons();
599  TEST_EXPECT_NEWICK(nSIMPLE, tree, "(" ORG_2 "," ORG_1 ");");
600 
601  // test reorder_tree
604 
605  for (size_t o1 = 0; o1<ARRAY_ELEMS(order); ++o1) {
606  TreeOrder to_order = order[o1];
607  for (size_t o2 = 0; o2<ARRAY_ELEMS(order); ++o2) {
608  TreeOrder from_order = order[o2];
609 
610  for (int rotate = 0; rotate<=1; ++rotate) {
611  tree->reorder_tree(from_order);
612  if (rotate) tree->rotate_subtree();
613  tree->reorder_tree(to_order);
614 
615  switch (to_order) {
616  case BIG_BRANCHES_TO_TOP: TEST_EXPECT_NEWICK(nSIMPLE, tree, "(" TOP_1 "," TOP_2 ");"); break;
617  case BIG_BRANCHES_TO_EDGE: TEST_EXPECT_NEWICK(nSIMPLE, tree, "(" EDG_1 "," BOT_2 ");"); break;
618  case BIG_BRANCHES_TO_BOTTOM: TEST_EXPECT_NEWICK(nSIMPLE, tree, "(" BOT_2 "," BOT_1 ");"); break;
619  default: TEST_REJECT(true); break;
620  }
621 
622  }
623  }
624  }
625 
626  // test rotate_subtree
628  tree->reorder_tree(BIG_BRANCHES_TO_TOP);
629  tree->rotate_subtree(); TEST_EXPECT_NEWICK(nSIMPLE, tree, "((LbnAlexa,(LbnzAlb4,LbnMarin)),((_MhuCaps,ThtNivea),((RsnAnta2,OnlGran2),((AticSea6,(RblMesop,RblAerol)),((PaoMaris,(MabSalin,MabPelag)),(MmbAlkal,(RsbElon4,DnrShiba)))))));");
630  tree->rotate_subtree(); TEST_EXPECT_NEWICK(nSIMPLE, tree, "(" TOP_1 "," TOP_2 ");");
631 
632 
633  // test set_root
635  TreeNode *AticSea6Grandpa = tree->findLeafNamed("AticSea6")->get_father()->get_father();
636  TEST_REJECT_NULL(AticSea6Grandpa);
637  TEST_EXPECT_VALID_TREE(AticSea6Grandpa);
638 
639  AticSea6Grandpa->set_root();
641  "((" ORG_1112 "," TOP_1111 ")," // AticSea6 is direct son of TOP_1111
642  "((" ORG_2 "," TOP_12 ")," ORG_112 "));");
643 
644  // test auto-detection of "best" root
646  tree->get_tree_root()->find_innermost_edge().set_root();
648  "((((LbnMarin:0.019,LbnzAlb4:0.003):0.016,LbnAlexa:0.032):0.122,(ThtNivea:0.230,_MhuCaps:0.194):0.427):0.076,"
649  "(((((DnrShiba:0.076,RsbElon4:0.053):0.034,MmbAlkal:0.069):0.016,((MabPelag:0.001,MabSalin:0.009):0.095,PaoMaris:0.092):0.036):0.030,((RblAerol:0.085,RblMesop:0.042):0.238,AticSea6:0.111):0.018):0.036,(OnlGran2:0.057,RsnAnta2:0.060):0.021):0.076);");
650 
652  destroy(tree);
653  free(comment);
654 }
655 
656 #endif // UNIT_TESTS
657 
658 // --------------------------------------------------------------------------------
GB_ERROR GBK_system(const char *system_command)
Definition: arb_msg.cxx:519
#define arb_assert(cond)
Definition: arb_assert.h:245
const char * GB_ERROR
Definition: arb_core.h:25
size_t GBT_count_leafs(const TreeNode *tree)
Definition: adtree.cxx:796
GBDATA * GB_open(const char *path, const char *opent)
Definition: ad_load.cxx:1363
void put(const char *elem)
Definition: arb_strarray.h:199
group_matcher all()
Definition: test_unit.h:1000
size_t size() const
Definition: arb_strarray.h:85
GB_ERROR GBT_write_tree_with_remark(GBDATA *gb_main, const char *tree_name, TreeNode *tree, const char *remark)
Definition: adtree.cxx:524
TreeNode * findLeafNamed(const char *wantedName)
Definition: TreeNode.cxx:274
virtual void set_root()
Definition: TreeNode.cxx:206
int ARB_main(int argc, char *argv[])
char * get_tree_remark() const
Definition: CT_ctree.cxx:145
#define TEST_STDOUT_CONTAINS(cmd, part)
char * ARB_strdup(const char *str)
Definition: arb_string.h:27
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:204
STL namespace.
char * ARB_strpartdup(const char *start, const char *end)
Definition: arb_string.h:51
#define EXIT_SUCCESS
Definition: arb_a2ps.c:154
int GB_unlink(const char *path)
Definition: arb_file.cxx:188
static GB_ERROR save_tree_as_newick(TreeNode *tree, const char *savename, const char *comment)
#define ARRAY_ELEMS(array)
Definition: arb_defs.h:19
bool empty() const
Definition: arb_strarray.h:86
GBT_LEN leftlen
Definition: TreeNode.h:132
#define DOWNCAST(totype, expr)
Definition: downcast.h:141
#define TEST_PUBLISH(testfunction)
Definition: test_unit.h:1484
GB_ERROR GB_await_error()
Definition: arb_msg.cxx:353
TREE_node_quoting
Definition: TreeWrite.h:34
#define TEST_EXPECT(cond)
Definition: test_unit.h:1312
static int weight[maxsites+1]
void GB_warningf(const char *templat,...)
Definition: arb_msg.cxx:490
#define TEST_EXPECT_NEWICK(format, tree, expected_newick)
Definition: test_unit.h:1448
#define is_equal_to_NULL()
Definition: test_unit.h:1017
GB_ERROR TREE_write_Newick(GBDATA *gb_main, const char *tree_name, const TREE_node_text_gen *node_gen, bool save_branchlengths, bool save_bootstraps, bool save_groupnames, bool pretty, TREE_node_quoting quoteMode, const char *path)
Definition: TreeWrite.cxx:336
void add(SizeAwareTree *&tree, const char *treename, double weight)
Definition: CT_ctree.hxx:168
#define TEST_REJECT(cond)
Definition: test_unit.h:1314
#define TEST_REJECT_NULL(n)
Definition: test_unit.h:1309
static void error(const char *msg)
Definition: mkptypes.cxx:96
TreeNode * TREE_load(const char *path, TreeRoot *troot, char **commentPtr, bool allow_length_scaling, char **warningPtr)
Definition: TreeRead.cxx:631
expectation_group & add(const expectation &e)
Definition: test_unit.h:801
#define that(thing)
Definition: test_unit.h:1032
#define TEST_EXPECT_VALID_TREE(tree)
Definition: TreeNode.h:619
#define TEST_OUTPUT_CONTAINS(cmd, expected_std, expected_err)
#define TEST_EXPECT_ZERO_OR_SHOW_ERRNO(iocond)
Definition: test_unit.h:1079
#define TEST_EXPECT_TEXTFILE_DIFFLINES_IGNORE_DATES(fgot, fwant, diff)
Definition: test_unit.h:1390
#define does_differ_from_NULL()
Definition: test_unit.h:1018
GBT_LEN rightlen
Definition: TreeNode.h:132
#define EXIT_FAILURE
Definition: arb_a2ps.c:157
#define is_equal_to(val)
Definition: test_unit.h:1014
#define TEST_EXPECTATION(EXPCTN)
Definition: test_unit.h:1037
#define textfiles_have_difflines(f1, f2, ed)
Definition: test_unit.h:1408
bool is_leaf() const
Definition: TreeNode.h:171
#define textfiles_have_difflines_ignoreDates(f1, f2, ed)
Definition: test_unit.h:1409
#define TEST_EXPECT_NULL(n)
Definition: test_unit.h:1307
static list< LineAttachedMessage > warnings
#define fulfills(pred, arg)
Definition: test_unit.h:1026
SizeAwareTree * get(size_t &different_species, GB_ERROR &error)
Definition: CT_ctree.hxx:200
char * name
Definition: TreeNode.h:134
TreeOrder
Definition: TreeNode.h:35
#define TEST_EXPECT_NO_ERROR(call)
Definition: test_unit.h:1107
#define NULp
Definition: cxxforward.h:97
bool ARB_strBeginsWith(const char *str, const char *with)
Definition: arb_str.h:42
GB_transaction ta(gb_var)
void destroy(TreeNode *that)
Definition: TreeNode.h:559
GBDATA * gb_main
Definition: adname.cxx:33
static char * create_tree_name(const char *savename)
#define TEST_EXPECT_EQUAL(expr, want)
Definition: test_unit.h:1283
static TreeNode * build_consensus_tree(const CharPtrArray &input_trees, GB_ERROR &error, size_t &different_species, double weight, char *&comment)
char * GBS_global_string_copy(const char *templat,...)
Definition: arb_msg.cxx:195
void GB_close(GBDATA *gbd)
Definition: arbdb.cxx:625
#define UNCOVERED()
Definition: arb_assert.h:380