source: tags/ms_r16q3/ARBDB/TreeNode.cxx

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