source: tags/ms_r18q1/ARBDB/TreeNode.cxx

Last change on this file was 17110, checked in by westram, 6 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.9 KB
Line 
1// ================================================================ //
2//                                                                  //
3//   File      : TreeNode.cxx                                       //
4//   Purpose   :                                                    //
5//                                                                  //
6//   Coded by Ralf Westram (coder@reallysoft.de) in December 2013   //
7//   Institute of Microbiology (Technical University Munich)        //
8//   http://www.arb-home.de/                                        //
9//                                                                  //
10// ================================================================ //
11
12#include "TreeNode.h"
13#include <arb_progress.h>
14#include <map>
15#include <set>
16#include <cmath> // needed with 4.4.3 (but not with 4.7.3)
17
18// ------------------
19//      TreeRoot
20
21TreeRoot::~TreeRoot() {
22    deleteWithNodes = false; // avoid recursive call of ~TreeRoot (obsolete?)
23    rt_assert(!rootNode);    // you have to call TreeRoot::predelete() before dtor! you can do this is dtor of that derived class, which defines makeNode/destroyNode
24    // Note: destroying nodes from here is impossible (leads to pure virtual call, as derived class instance of 'this' is already under destruction)
25}
26
27void TreeRoot::change_root(TreeNode *oldroot, TreeNode *newroot) {
28    rt_assert(rootNode == oldroot);
29    rt_assert(implicated(newroot, !newroot->father));
30    rootNode = newroot;
31
32    if (oldroot && oldroot->get_tree_root() && !oldroot->is_inside(newroot)) oldroot->set_tree_root(NULp); // unlink from this
33    if (newroot && newroot->get_tree_root() != this) newroot->set_tree_root(this); // link to this
34}
35
36// --------------------
37//      TreeNode
38
39#if defined(PROVIDE_TREE_STRUCTURE_TESTS)
40
41Validity TreeNode::is_valid() const {
42    rt_assert(knownNonNull(this));
43    Validity valid;
44
45    TreeRoot *troot = get_tree_root();
46    if (troot) {
47        if (is_leaf()) {
48            valid = Validity(!rightson && !leftson, "leaf has son");
49        }
50        else {
51            valid            = Validity(rightson && leftson, "inner node lacks sons");
52            if (valid) valid = get_rightson()->is_valid();
53            if (valid) valid = get_leftson()->is_valid();
54        }
55        if (father) {
56            if (valid) valid = Validity(is_inside(get_father()), "node not inside father subtree");
57            if (valid) valid = Validity(troot->get_root_node()->is_ancestor_of(this), "root is not nodes ancestor");
58            if (valid) valid = Validity(get_father()->get_tree_root() == troot, "node and father have different TreeRoot");
59        }
60        else {
61            if (valid) valid = Validity(troot->get_root_node() == this, "node has no father, but isn't root-node");
62            if (valid) valid = Validity(!is_leaf(), "root-node is leaf"); // leaf@root (tree has to have at least 2 leafs)
63        }
64    }
65    else { // removed node (may be incomplete)
66        if (is_leaf()) {
67            valid = Validity(!rightson && !leftson, "(removed) leaf has son");
68        }
69        else {
70            if (rightson)         valid = get_rightson()->is_valid();
71            if (leftson && valid) valid = get_leftson()->is_valid();
72        }
73        if (father) {
74            if (valid) valid = Validity(is_inside(get_father()), "(removed) node not inside father subtree");
75            if (valid) valid = Validity(get_father()->get_tree_root() == troot, "(removed) node and father have different TreeRoot");
76        }
77    }
78    return valid;
79}
80#endif // PROVIDE_TREE_STRUCTURE_TESTS
81
82void TreeNode::set_tree_root(TreeRoot *new_root) {
83    if (tree_root != new_root) {
84        tree_root = new_root;
85        if (leftson) get_leftson()->set_tree_root(new_root);
86        if (rightson) get_rightson()->set_tree_root(new_root);
87    }
88}
89
90void TreeNode::reorder_subtree(TreeOrder mode) {
91    static const char *smallest_leafname; // has to be set to the alphabetically smallest name (when function exits)
92
93    if (is_leaf()) {
94        smallest_leafname = name;
95    }
96    else {
97        int leftsize  = get_leftson() ->get_leaf_count();
98        int rightsize = get_rightson()->get_leaf_count();
99
100        {
101            bool big_at_top    = leftsize>rightsize;
102            bool big_at_bottom = leftsize<rightsize;
103            bool swap_branches = (mode&ORDER_BIG_DOWN) ? big_at_top : big_at_bottom;
104            if (swap_branches) swap_sons();
105        }
106
107        TreeOrder lmode, rmode;
108        if (mode & (ORDER_BIG_TO_EDGE|ORDER_BIG_TO_CENTER)) { // symmetric
109            if (mode & ORDER_ALTERNATING) mode = TreeOrder(mode^(ORDER_BIG_TO_EDGE|ORDER_BIG_TO_CENTER));
110
111            if (mode & ORDER_BIG_TO_CENTER) {
112                lmode = TreeOrder(mode | ORDER_BIG_DOWN);
113                rmode = TreeOrder(mode & ~ORDER_BIG_DOWN);
114            }
115            else {
116                lmode = TreeOrder(mode & ~ORDER_BIG_DOWN);
117                rmode = TreeOrder(mode | ORDER_BIG_DOWN);
118            }
119        }
120        else { // asymmetric
121            if (mode & ORDER_ALTERNATING) mode = TreeOrder(mode^ORDER_BIG_DOWN);
122
123            lmode = mode;
124            rmode = mode;
125        }
126
127        get_leftson()->reorder_subtree(lmode);
128        const char *leftleafname = smallest_leafname;
129
130        get_rightson()->reorder_subtree(rmode);
131        const char *rightleafname = smallest_leafname;
132
133        if (leftleafname && rightleafname) {
134            int name_cmp = strcmp(leftleafname, rightleafname);
135            if (name_cmp <= 0) {
136                smallest_leafname = leftleafname;
137            }
138            else {
139                smallest_leafname = rightleafname;
140                if (leftsize == rightsize) { // if sizes of subtrees are equal and rightleafname<leftleafname -> swap branches
141                    const char *smallest_leafname_save = smallest_leafname;
142
143                    swap_sons();
144                    get_leftson ()->reorder_subtree(lmode); rt_assert(strcmp(smallest_leafname, rightleafname)== 0);
145                    get_rightson()->reorder_subtree(rmode); rt_assert(strcmp(smallest_leafname, leftleafname) == 0);
146
147                    smallest_leafname = smallest_leafname_save;
148                }
149            }
150        }
151    }
152    rt_assert(smallest_leafname);
153}
154
155void TreeNode::reorder_tree(TreeOrder mode) {
156    /*! beautify tree (does not change topology, only swaps branches)
157     */
158    compute_tree();
159    reorder_subtree(mode);
160}
161
162void TreeNode::rotate_subtree() {
163    if (!is_leaf()) {
164        swap_sons();
165        get_leftson()->rotate_subtree();
166        get_rightson()->rotate_subtree();
167    }
168}
169
170void TreeNode::keelOver(TreeNode *prev, TreeNode *next, double len) {
171    /*! atomic part of set_root operation that keels over edges between new and old root
172     * @param prev previously a son of 'this', will become father
173     * @param next previously the father of 'this', will become son
174     * @param len  length of branch to nextSon
175     */
176
177    if (leftson == prev) {
178        leftson = next;
179        leftlen = len;
180
181        if (keeledOver) {
182            if (inverseLeft) keeledOver = false;
183        }
184        else {
185            keeledOver  = true;
186            inverseLeft = true;
187        }
188    }
189    else {
190        rightson = next;
191        rightlen = len;
192
193        if (keeledOver) {
194            if (!inverseLeft) keeledOver = false;
195        }
196        else {
197            keeledOver  = true;
198            inverseLeft = false;
199        }
200    }
201    father = prev;
202}
203
204void TreeNode::set_root() {
205    /*! set the root at parent edge of this
206     * pointers to tree-nodes remain valid, but all parent-nodes of this change their meaning
207     * (afterwards they will point to [father+brother] instead of [this+brother])
208     * esp. pointers to the root-node will still point to the root-node (which only changed children)
209     */
210
211    if (at_root()) return; // already root
212
213    TreeNode *old_root    = get_root_node();
214    TreeNode *old_brother = is_inside(old_root->get_leftson()) ? old_root->get_rightson() : old_root->get_leftson();
215
216    // move remark branches to top
217    {
218        char *remark = nulldup(get_remark());
219        for (TreeNode *node = this; node->father; node = node->get_father()) {
220            remark = node->swap_remark(remark);
221        }
222        free(remark);
223    }
224
225    GBT_LEN old_root_len = old_root->leftlen + old_root->rightlen;
226
227    // new node & this init
228    old_root->leftson  = this;
229    old_root->rightson = father; // will be set later
230
231    if (father->leftson == this) {
232        old_root->leftlen = old_root->rightlen = father->leftlen*.5;
233    }
234    else {
235        old_root->leftlen = old_root->rightlen = father->rightlen*.5;
236    }
237
238    TreeNode *next = get_father()->get_father();
239    TreeNode *prev = old_root;
240    TreeNode *pntr = get_father();
241
242    if (father->leftson == this)    father->leftson = old_root; // to set the flag correctly
243
244    // loop from father to son of root, rotate tree
245    while  (next->father) {
246        double len = (next->leftson == pntr) ? next->leftlen : next->rightlen;
247
248        pntr->keelOver(prev, next, len);
249
250        prev = pntr;
251        pntr = next;
252        next = next->get_father();
253    }
254    // now 'next' points to the old root, which has been destroyed above
255    // 'pntr' points to one former son-of-root (the one nearer to new root)
256    //
257    // pointer at oldroot
258    // pntr == brother before old root == next
259
260    pntr->keelOver(prev, old_brother, old_root_len);
261
262    old_brother->father = pntr;
263    father              = old_root;
264
265    rt_assert(get_root_node() == old_root);
266}
267
268TreeNode *TreeNode::findLeafNamed(const char *wantedName) {
269    TreeNode *found = NULp;
270    if (is_leaf()) {
271        if (name && strcmp(name, wantedName) == 0) found = this;
272    }
273    else {
274        found             = get_leftson()->findLeafNamed(wantedName);
275        if (!found) found = get_rightson()->findLeafNamed(wantedName);
276    }
277    return found;
278}
279
280// ----------------------------
281//      find_innermost_edge
282
283class NodeLeafDistance {
284    GBT_LEN downdist, updist;
285    enum { NLD_NODIST = 0, NLD_DOWNDIST, NLD_BOTHDIST } state;
286
287public:
288
289    NodeLeafDistance()
290        : downdist(-1.0),
291          updist(-1.0),
292          state(NLD_NODIST)
293    {}
294
295    GBT_LEN get_downdist() const { rt_assert(state >= NLD_DOWNDIST); return downdist; }
296    void set_downdist(GBT_LEN DownDist) {
297        if (state < NLD_DOWNDIST) state = NLD_DOWNDIST;
298        downdist = DownDist;
299    }
300
301    GBT_LEN get_updist() const { rt_assert(state >= NLD_BOTHDIST); return updist; }
302    void set_updist(GBT_LEN UpDist) {
303        if (state < NLD_BOTHDIST) state = NLD_BOTHDIST;
304        updist = UpDist;
305    }
306
307};
308
309class EdgeFinder {
310    std::map<TreeNode*, NodeLeafDistance> data; // maximum distance to farthest leaf
311
312    ARB_edge innermost;
313    double   min_distdiff; // abs diff between up- and downdiff
314
315    GBT_LEN calc_distdiff(GBT_LEN d1, GBT_LEN d2) { return fabs(d1-d2); }
316
317    void insert_tree(TreeNode *node) {
318        if (node->is_leaf()) {
319            data[node].set_downdist(0.0);
320        }
321        else {
322            insert_tree(node->get_leftson());
323            insert_tree(node->get_rightson());
324
325            data[node].set_downdist(std::max(data[node->get_leftson()].get_downdist()+node->leftlen,
326                                             data[node->get_rightson()].get_downdist()+node->rightlen));
327        }
328    }
329
330    void findBetterEdge_sub(TreeNode *node) {
331        TreeNode *father  = node->get_father();
332        TreeNode *brother = node->get_brother();
333
334        GBT_LEN len      = node->get_branchlength();
335        GBT_LEN brothLen = brother->get_branchlength();
336
337        GBT_LEN upDist   = std::max(data[father].get_updist(), data[brother].get_downdist()+brothLen);
338        GBT_LEN downDist = data[node].get_downdist();
339
340        {
341            GBT_LEN edge_dd = calc_distdiff(upDist, downDist);
342            if (edge_dd<min_distdiff) { // found better edge
343                innermost    = ARB_edge(node, father);
344                min_distdiff = edge_dd;
345            }
346        }
347
348        data[node].set_updist(upDist+len);
349
350        if (!node->is_leaf()) {
351            findBetterEdge_sub(node->get_leftson());
352            findBetterEdge_sub(node->get_rightson());
353        }
354    }
355
356    void findBetterEdge(TreeNode *node) {
357        if (!node->is_leaf()) {
358            findBetterEdge_sub(node->get_leftson());
359            findBetterEdge_sub(node->get_rightson());
360        }
361    }
362
363public:
364    EdgeFinder(TreeNode *rootNode)
365        : innermost(rootNode->get_leftson(), rootNode->get_rightson()) // root-edge
366    {
367        insert_tree(rootNode);
368
369        TreeNode *lson = rootNode->get_leftson();
370        TreeNode *rson = rootNode->get_rightson();
371
372        GBT_LEN rootEdgeLen = rootNode->leftlen + rootNode->rightlen;
373
374        GBT_LEN lddist = data[lson].get_downdist();
375        GBT_LEN rddist = data[rson].get_downdist();
376
377        data[lson].set_updist(rddist+rootEdgeLen);
378        data[rson].set_updist(lddist+rootEdgeLen);
379
380        min_distdiff = calc_distdiff(lddist, rddist);
381
382        findBetterEdge(lson);
383        findBetterEdge(rson);
384    }
385
386    const ARB_edge& innermost_edge() const { return innermost; }
387};
388
389ARB_edge TreeRoot::find_innermost_edge() {
390    EdgeFinder edgeFinder(get_root_node());
391    return edgeFinder.innermost_edge();
392}
393
394// ------------------------
395//      multifurcation
396
397class TreeNode::LengthCollector {
398    typedef std::map<TreeNode*,GBT_LEN> LengthMap;
399    typedef std::set<TreeNode*>         NodeSet;
400
401    LengthMap eliminatedParentLength;
402    LengthMap addedParentLength;
403
404public:
405    void eliminate_parent_edge(TreeNode *node) {
406        rt_assert(!node->is_root_node());
407        eliminatedParentLength[node] += parentEdge(node).eliminate();
408    }
409
410    void add_parent_length(TreeNode *node, GBT_LEN addLen) {
411        rt_assert(!node->is_root_node());
412        addedParentLength[node] += addLen;
413    }
414
415    void independent_distribution(bool useProgress) {
416        // step 2: (see caller)
417        arb_progress *progress    = NULp;
418        int           redistCount = 0;
419        if (useProgress) progress = new arb_progress("Distributing eliminated lengths", eliminatedParentLength.size());
420
421        while (!eliminatedParentLength.empty()) { // got eliminated lengths which need to be distributed
422            for (LengthMap::iterator from = eliminatedParentLength.begin(); from != eliminatedParentLength.end(); ++from) {
423                ARB_edge elimEdge = parentEdge(from->first);
424                GBT_LEN  elimLen  = from->second;
425
426                elimEdge.virtually_distribute_length(elimLen, *this);
427                if (progress) ++*progress;
428            }
429            eliminatedParentLength.clear(); // all distributed!
430
431            // handle special cases where distributed length is negative and results in negative destination branches.
432            // Avoid generating negative dest. branchlengths by
433            // - eliminating the dest. branch
434            // - redistributing the additional (negative) length (may cause additional negative lengths on other dest. branches)
435
436            NodeSet handled;
437            for (LengthMap::iterator to = addedParentLength.begin(); to != addedParentLength.end(); ++to) {
438                ARB_edge affectedEdge     = parentEdge(to->first);
439                GBT_LEN  additionalLen    = to->second;
440                double   effective_length = affectedEdge.length() + additionalLen;
441
442                if (effective_length<=0.0) { // negative or zero
443                    affectedEdge.set_length(effective_length);
444                    eliminate_parent_edge(to->first); // adds entry to eliminatedParentLength and causes another additional loop
445                    handled.insert(to->first);
446                }
447            }
448
449            if (progress && !eliminatedParentLength.empty()) {
450                delete progress;
451                ++redistCount;
452                progress = new arb_progress(GBS_global_string("Redistributing negative lengths (#%i)", redistCount), eliminatedParentLength.size());
453            }
454
455            // remove all redistributed nodes
456            for (NodeSet::iterator del = handled.begin(); del != handled.end(); ++del) {
457                addedParentLength.erase(*del);
458            }
459        }
460
461        // step 3:
462        for (LengthMap::iterator to = addedParentLength.begin(); to != addedParentLength.end(); ++to) {
463            ARB_edge affectedEdge     = parentEdge(to->first);
464            GBT_LEN  additionalLen    = to->second;
465            double   effective_length = affectedEdge.length() + additionalLen;
466
467            affectedEdge.set_length(effective_length);
468        }
469
470        if (progress) delete progress;
471    }
472};
473
474GBT_LEN ARB_edge::adjacent_distance() const {
475    //! return length of edges starting from this->dest()
476
477    if (is_edge_to_leaf()) return 0.0;
478    return next().length_or_adjacent_distance() + counter_next().length_or_adjacent_distance();
479}
480
481void ARB_edge::virtually_add_or_distribute_length_forward(GBT_LEN len, TreeNode::LengthCollector& collect) const {
482    rt_assert(!is_nan_or_inf(len));
483    if (length() > 0.0) {
484        collect.add_parent_length(son(), len);
485    }
486    else {
487        if (len != 0.0) virtually_distribute_length_forward(len, collect);
488    }
489}
490
491
492void ARB_edge::virtually_distribute_length_forward(GBT_LEN len, TreeNode::LengthCollector& collect) const {
493    /*! distribute length to edges adjacent in edge direction (i.e. edges starting from this->dest())
494     * Split 'len' proportional to adjacent edges lengths.
495     *
496     * Note: length will not be distributed to tree-struction itself (yet), but collected in 'collect'
497     */
498
499    rt_assert(is_normal(len));
500    rt_assert(!is_edge_to_leaf()); // cannot forward anything (nothing beyond leafs)
501
502    ARB_edge e1 = next();
503    ARB_edge e2 = counter_next();
504
505    GBT_LEN d1 = e1.length_or_adjacent_distance();
506    GBT_LEN d2 = e2.length_or_adjacent_distance();
507
508    len = len/(d1+d2);
509
510    e1.virtually_add_or_distribute_length_forward(len*d1, collect);
511    e2.virtually_add_or_distribute_length_forward(len*d2, collect);
512}
513
514void ARB_edge::virtually_distribute_length(GBT_LEN len, TreeNode::LengthCollector& collect) const {
515    /*! distribute length to all adjacent edges.
516     * Longer edges receive more than shorter ones.
517     *
518     * Edges with length zero will not be changed, instead both edges "beyond"
519     * the edge will be affected (they will be affected equally to direct edges,
520     * because edges at multifurcations are considered to BE direct edges).
521     *
522     * Note: length will not be distributed to tree-struction itself (yet), but collected in 'collect'
523     */
524
525    ARB_edge backEdge = inverse();
526    GBT_LEN len_fwd, len_bwd;
527    {
528        GBT_LEN dist_fwd = adjacent_distance();
529        GBT_LEN dist_bwd = backEdge.adjacent_distance();
530        GBT_LEN lenW     = len/(dist_fwd+dist_bwd);
531        len_fwd          = lenW*dist_fwd;
532        len_bwd          = lenW*dist_bwd;
533
534    }
535
536    if (is_normal(len_fwd)) virtually_distribute_length_forward(len_fwd, collect);
537    if (is_normal(len_bwd)) backEdge.virtually_distribute_length_forward(len_bwd, collect);
538}
539
540void TreeNode::eliminate_and_collect(const multifurc_limits& below, LengthCollector& collect) {
541    /*! eliminate edges specified by 'below' and
542     * store their length in 'collect' for later distribution.
543     */
544    rt_assert(!is_root_node());
545    if (!is_leaf() || below.applyAtLeafs) {
546        double value;
547        switch (parse_bootstrap(value)) {
548            case REMARK_NONE:
549                value = 100.0;
550                // fall-through
551            case REMARK_BOOTSTRAP:
552                if (value<below.bootstrap && get_branchlength_unrooted()<below.branchlength) {
553                    collect.eliminate_parent_edge(this);
554                }
555                break;
556
557            case REMARK_OTHER: break;
558        }
559    }
560
561    if (!is_leaf()) {
562        get_leftson() ->eliminate_and_collect(below, collect);
563        get_rightson()->eliminate_and_collect(below, collect);
564    }
565}
566
567void ARB_edge::multifurcate() {
568    /*! eliminate edge and distribute length to adjacent edges
569     * - sets its length to zero
570     * - removes remark (bootstrap)
571     * - distributes length to neighbour-branches
572     */
573    TreeNode::LengthCollector collector;
574    collector.eliminate_parent_edge(son());
575    collector.independent_distribution(false);
576}
577void TreeNode::multifurcate() {
578    /*! eliminate branch from 'this' to 'father' (or brother @ root)
579     * @see ARB_edge::multifurcate()
580     */
581    rt_assert(father); // cannot multifurcate at root; call with son of root to multifurcate root-edge
582    if (father) parentEdge(this).multifurcate();
583}
584
585void TreeNode::set_branchlength_preserving(GBT_LEN new_len) {
586    /*! set branchlength to 'new_len' while preserving overall distance in tree.
587     *
588     * Always works on unrooted tree (i.e. lengths @ root are treated correctly).
589     * Length is preserved as in multifurcate()
590     */
591
592    GBT_LEN old_len = get_branchlength_unrooted();
593    GBT_LEN change  = new_len-old_len;
594
595    char *old_remark = nulldup(get_remark());
596
597    // distribute the negative 'change' to neighbours:
598    set_branchlength_unrooted(-change);
599    multifurcate();
600
601    set_branchlength_unrooted(new_len);
602    use_as_remark(old_remark); // restore remark (was removed by multifurcate())
603}
604
605void TreeNode::multifurcate_whole_tree(const multifurc_limits& below) {
606    /*! multifurcate all branches specified by 'below'
607     * - step 1: eliminate all branches, store eliminated lengths
608     * - step 2: calculate length distribution for all adjacent branches (proportionally to original length of each branch)
609     * - step 3: apply distributed length
610     */
611    TreeNode        *root = get_root_node();
612    LengthCollector  collector;
613    arb_progress progress("Multifurcating tree");
614
615    // step 1:
616    progress.subtitle("Collecting branches to eliminate");
617    root->get_leftson()->eliminate_and_collect(below, collector);
618    root->get_rightson()->eliminate_and_collect(below, collector);
619    // root-edge is handled twice by the above calls.
620    // Unproblematic: first call will eliminate root-edge, so second call will do nothing.
621
622    // step 2 and 3:
623    collector.independent_distribution(true);
624}
625
626TreeNode::bs100_mode TreeNode::toggle_bootstrap100(bs100_mode mode) {
627    if (!is_leaf()) {
628        if (!is_root_node()) {
629            double bootstrap;
630            switch (parse_bootstrap(bootstrap)) {
631                case REMARK_NONE:
632                case REMARK_OTHER:
633                    switch (mode) {
634                        case BS_UNDECIDED: mode = BS_INSERT;   FALLTHROUGH;
635                        case BS_INSERT:    set_bootstrap(100); FALLTHROUGH;
636                        case BS_REMOVE:    break;
637                    }
638                    break;
639                case REMARK_BOOTSTRAP:
640                    if (bootstrap >= 99.5) {
641                        switch (mode) {
642                            case BS_UNDECIDED: mode = BS_REMOVE; FALLTHROUGH;
643                            case BS_REMOVE:    remove_remark();  FALLTHROUGH;
644                            case BS_INSERT:    break;
645                        }
646                    }
647                    break;
648            }
649        }
650
651        mode = get_leftson()->toggle_bootstrap100(mode);
652        mode = get_rightson()->toggle_bootstrap100(mode);
653    }
654    return mode;
655}
656void TreeNode::remove_bootstrap() {
657    freenull(remark_branch);
658    if (!is_leaf()) {
659        get_leftson()->remove_bootstrap();
660        get_rightson()->remove_bootstrap();
661    }
662}
663void TreeNode::reset_branchlengths() {
664    if (!is_leaf()) {
665        leftlen = rightlen = DEFAULT_BRANCH_LENGTH;
666
667        get_leftson()->reset_branchlengths();
668        get_rightson()->reset_branchlengths();
669    }
670}
671
672void TreeNode::scale_branchlengths(double factor) {
673    if (!is_leaf()) {
674        leftlen  *= factor;
675        rightlen *= factor;
676
677        get_leftson()->scale_branchlengths(factor);
678        get_rightson()->scale_branchlengths(factor);
679    }
680}
681
682GBT_LEN TreeNode::sum_child_lengths() const {
683    if (is_leaf()) return 0.0;
684    return
685        leftlen +
686        rightlen +
687        get_leftson()->sum_child_lengths() +
688        get_rightson()->sum_child_lengths();
689}
690
691void TreeNode::bootstrap2branchlen() {
692    //! copy bootstraps to branchlengths
693    if (is_leaf()) {
694        set_branchlength_unrooted(DEFAULT_BRANCH_LENGTH);
695    }
696    else {
697        if (father) {
698            double         bootstrap;
699            GBT_RemarkType rtype = parse_bootstrap(bootstrap);
700
701            if (rtype == REMARK_BOOTSTRAP) {
702                double len = bootstrap/100.0;
703                set_branchlength_unrooted(len);
704            }
705            else {
706                set_branchlength_unrooted(1.0); // no bootstrap means "100%"
707            }
708        }
709        get_leftson()->bootstrap2branchlen();
710        get_rightson()->bootstrap2branchlen();
711    }
712}
713
714void TreeNode::branchlen2bootstrap() {
715    //! copy branchlengths to bootstraps
716    remove_remark();
717    if (!is_leaf()) {
718        if (!is_root_node()) {
719            set_bootstrap(get_branchlength_unrooted()*100.0);
720        }
721        get_leftson()->branchlen2bootstrap();
722        get_rightson()->branchlen2bootstrap();
723    }
724}
725
726TreeNode *TreeNode::fixDeletedSon() {
727    // fix node after one son has been deleted
728    TreeNode *result = NULp;
729
730    if (leftson) {
731        gb_assert(!rightson);
732        result  = get_leftson();
733        leftson = NULp;
734    }
735    else {
736        gb_assert(!leftson);
737        gb_assert(rightson);
738
739        result   = get_rightson();
740        rightson = NULp;
741    }
742
743    // now 'result' contains the lasting tree
744    result->father = father;
745
746    if (remark_branch && !result->remark_branch) { // rescue remarks if possible
747        result->remark_branch    = remark_branch;
748        remark_branch = NULp;
749    }
750    if (gb_node && !result->gb_node) { // rescue group if possible
751        result->gb_node = gb_node;
752        gb_node         = NULp;
753    }
754
755    if (!result->father) {
756        get_tree_root()->change_root(this, result);
757    }
758
759    gb_assert(!is_root_node());
760
761    forget_origin();
762    forget_relatives();
763    delete this;
764
765    return result;
766}
767
768const TreeNode *TreeNode::ancestor_common_with(const TreeNode *other) const {
769    if (this == other) return this;
770    if (is_ancestor_of(other)) return this;
771    if (other->is_ancestor_of(this)) return other;
772    return get_father()->ancestor_common_with(other->get_father());
773}
774
775// --------------------------------------------------------------------------------
776
777#ifdef UNIT_TESTS
778#ifndef TEST_UNIT_H
779#include <test_unit.h>
780#endif
781
782void TEST_tree_iterator() {
783    GB_shell  shell;
784    GBDATA   *gb_main = GB_open("TEST_trees.arb", "r");
785    {
786        GB_transaction  ta(gb_main);
787        TreeNode       *tree = GBT_read_tree(gb_main, "tree_removal", new SimpleRoot);
788
789        int leafs = GBT_count_leafs(tree);
790        TEST_EXPECT_EQUAL(leafs, 17);
791        TEST_EXPECT_EQUAL(leafs_2_edges(leafs, UNROOTED), 31);
792
793        int iter_steps = ARB_edge::iteration_count(leafs);
794        TEST_EXPECT_EQUAL(iter_steps, 62);
795
796        const ARB_edge start = rootEdge(tree->get_tree_root());
797
798        // iterate forward + count (until same edge reached)
799        int      count       = 0;
800        int      count_leafs = 0;
801        ARB_edge edge        = start;
802        do {
803            ARB_edge next = edge.next();
804            TEST_EXPECT(next.previous() == edge); // test reverse operation
805            edge = next;
806            ++count;
807            if (edge.is_edge_to_leaf()) ++count_leafs;
808        }
809        while (edge != start);
810        TEST_EXPECT_EQUAL(count, iter_steps);
811        TEST_EXPECT_EQUAL(count_leafs, leafs);
812
813        // iterate backward + count (until same edge reached)
814        count       = 0;
815        count_leafs = 0;
816        edge        = start;
817        do {
818            ARB_edge next = edge.previous();
819            TEST_EXPECT(next.next() == edge); // test reverse operation
820            edge = next;
821            ++count;
822            if (edge.is_edge_to_leaf()) ++count_leafs;
823        }
824        while (edge != start);
825        TEST_EXPECT_EQUAL(count, iter_steps);
826        TEST_EXPECT_EQUAL(count_leafs, leafs);
827
828        if (tree) {
829            gb_assert(tree->is_root_node());
830            destroy(tree);
831        }
832    }
833    GB_close(gb_main);
834}
835
836TEST_PUBLISH(TEST_tree_iterator);
837
838#endif // UNIT_TESTS
839
840// --------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.