root/trunk/DIST/DI_clustertree.cxx

Revision 7186, 13.8 KB (checked in by westram, 15 months ago)

merges [7097] [7098] [7100] [7101] [7102] [7103] [7105] from refactor

  • use arb_progress instead of aw_openstatus, aw_closestatus and aw_status
    • allows nested progress bars
    • avoids repeatedly popping up progress bars
    • avoids passing down info about progress to callees or bookkeeping it in method-objects and similar
    • removed many useless status messages (e.g. those that were only visible for ms)
    • corrected incrementation / limit for many progress bars (esp. matrix-calculations, parsimony)
  • hide aw_open/close/status inside libAW
  • hide rests of GB_status inside libCORE
  • replaced ARB_null_status by arb_suppress_progress
    • suppress progress display in unit-tests
  • added GBT_count_alignments
  • stuffed a few memleaks on the way
  • disabled some deprecation warnings
  • use arb_progress in ptserver
  • avoid zero progress in GDE export
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : DI_clustertree.cxx                                //
4//   Purpose   :                                                   //
5//                                                                 //
6//   Coded by Ralf Westram (coder@reallysoft.de) in October 2009   //
7//   Institute of Microbiology (Technical University Munich)       //
8//   http://www.arb-home.de/                                       //
9//                                                                 //
10// =============================================================== //
11
12#include "di_clustertree.hxx"
13#include <arb_progress.h>
14#include <set>
15#include <cmath>
16#include <limits>
17
18using namespace std;
19
20typedef std::set<LeafRelation> SortedPairValues; // iterator runs from small to big values
21
22// ------------------------
23//      ClusterTreeRoot
24
25
26ClusterTreeRoot::ClusterTreeRoot(AliView *aliview, AP_sequence *seqTemplate_, AP_FLOAT maxDistance_, size_t minClusterSize_)
27    : ARB_tree_root(aliview, ClusterTree(0), seqTemplate_, false)
28    , maxDistance(maxDistance_)
29    , minClusterSize(minClusterSize_)
30{
31
32}
33
34ClusterTreeRoot::~ClusterTreeRoot() {
35}
36
37#if defined(DEBUG)
38struct ClusterStats {
39    size_t clusters;
40    size_t subclusters;
41    size_t loadedSequences;
42
43    ClusterStats()
44        : clusters(0)
45        , subclusters(0)
46        , loadedSequences(0)
47    {}
48};
49
50static void collectStats(ClusterTree *node, ClusterStats *stats) {
51    switch (node->get_state()) {
52        case CS_IS_CLUSTER: stats->clusters++; break;
53        case CS_SUB_CLUSTER: stats->subclusters++; break;
54        default: break;
55    }
56    if (node->is_leaf) {
57        AP_sequence *seq = node->get_seq();
58        if (seq->got_sequence()) stats->loadedSequences++;
59    }
60    else {
61        collectStats(node->get_leftson(), stats);
62        collectStats(node->get_rightson(), stats);
63    }
64}
65#endif // DEBUG
66
67GB_ERROR ClusterTreeRoot::find_clusters() {
68    ClusterTree *root = get_root_node();
69
70    root->init_tree();
71#if defined(DEBUG)
72    printf("----------------------------------------\n");
73    printf("maxDistance:       %f\n", maxDistance);
74    printf("minClusterSize:    %zu\n", minClusterSize);
75    printf("Leafs in tree:     %zu\n", root->get_leaf_count());
76    printf("Possible clusters: %zu\n", root->get_cluster_count());
77#endif // DEBUG
78
79    arb_progress cluster_progress(root->get_cluster_count());
80    cluster_progress.auto_subtitles("Cluster");
81
82    GB_ERROR error = NULL;
83
84    try {
85        root->detect_clusters(cluster_progress);
86    }
87    catch (const char *msg) { error = msg; }
88    catch (...) { cl_assert(0); }
89
90    if (error) {
91        // avoid further access after error
92        change_root(root, NULL);
93        delete root;
94    }
95    else {
96#if defined(DEBUG)
97        ClusterStats stats;
98        collectStats(root, &stats);
99
100        printf("Found clusters:::::::: %zu\n", stats.clusters);
101        printf("Found subclusters::::: %zu\n", stats.subclusters);
102        printf("Loaded sequences:::::: %zu (%5.2f%%)\n",
103               stats.loadedSequences,
104               (100.0*stats.loadedSequences)/root->get_leaf_count());
105
106#if defined(TRACE_DIST_CALC)
107        size_t distances         = root->get_calculated_distances();
108        size_t leafs             = root->get_leaf_count();
109        size_t existingDistances = (leafs*leafs)/2-1;
110
111        printf("Calculated distances:: %zu (%5.2f%%)\n",
112               distances,
113               (100.0*distances)/existingDistances);
114#endif                                              // TRACE_DIST_CALC
115
116#endif                                              // DEBUG
117    }
118
119    return error;
120}
121
122// --------------------
123//      ClusterTree
124
125ClusterTree *ClusterTree::get_cluster(size_t num) {
126    cl_assert(num < get_cluster_count());
127
128    if (num == 0) return this;
129
130    ClusterTree *lson = get_leftson();
131    if (lson->get_cluster_count() <= num) {
132        return get_rightson()->get_cluster(num - lson->get_cluster_count());
133    }
134    return lson->get_cluster(num);
135}
136
137void ClusterTree::init_tree() {
138    cl_assert(state == CS_UNKNOWN);
139
140#if defined(TRACE_DIST_CALC)
141    calculatedDistances = 0;
142#endif // TRACE_DIST_CALC
143
144    if (get_father()) {
145        depth = get_father()->get_depth()+1;
146    }
147    else {
148        depth = 1;
149        cl_assert(is_root_node());
150    }
151
152    if (is_leaf) {
153        leaf_count = 1;
154        clus_count = 0;
155        state      = CS_TOO_SMALL;
156    }
157    else {
158        ClusterTree *lson = get_leftson();
159        ClusterTree *rson = get_rightson();
160
161        lson->init_tree();
162        rson->init_tree();
163
164        leaf_count = lson->get_leaf_count() + rson->get_leaf_count();
165
166        ClusterTreeRoot *troot = get_tree_root();
167        if (leaf_count<troot->get_minClusterSize()) {
168            state      = CS_TOO_SMALL;
169            clus_count = 0;
170        }
171        else {
172            state      = CS_MAYBE_CLUSTER;
173            clus_count = lson->get_cluster_count() + rson->get_cluster_count() + 1;
174            min_bases  = numeric_limits<AP_FLOAT>::infinity();
175        }
176    }
177   
178    cl_assert(state != CS_UNKNOWN);
179}
180
181void ClusterTree::detect_clusters(arb_progress& progress) {
182    if (state == CS_MAYBE_CLUSTER) {
183        cl_assert(!is_leaf);
184
185        ClusterTree *lson = get_leftson();
186        ClusterTree *rson = get_rightson();
187
188        lson->detect_clusters(progress);
189        rson->detect_clusters(progress);
190
191#if defined(TRACE_DIST_CALC)
192        calculatedDistances += get_leftson()->calculatedDistances;
193        calculatedDistances += get_rightson()->calculatedDistances;
194#endif // TRACE_DIST_CALC
195
196        if (lson->get_state() == CS_NO_CLUSTER || rson->get_state() == CS_NO_CLUSTER) {
197            // one son is no cluster -> can't be cluster myself
198            state = CS_NO_CLUSTER;
199        }
200        else {
201            state = CS_IS_CLUSTER;                  // assume this is a cluster
202
203            // Get set of branches (sorted by branch distance)
204
205            get_branch_dists();                     // calculates branchDists
206            SortedPairValues pairsByBranchDistance; // biggest branch distances at end
207            {
208                LeafRelationCIter bd_end = branchDists->end();
209                for (LeafRelationCIter bd = branchDists->begin(); bd != bd_end; ++bd) {
210                    pairsByBranchDistance.insert(LeafRelation(bd->first, bd->second));
211                }
212            }
213
214            cl_assert(pairsByBranchDistance.size() == possible_relations());
215
216            // calculate real sequence distance
217            // * stop when distance > maxDistance is detected
218            // * calculate longest branchdistance first
219            //   (Assumption is: big branch distance <=> big sequence distance)
220
221            AP_FLOAT maxDistance       = get_tree_root()->get_maxDistance();
222            AP_FLOAT worstDistanceSeen = -1.0;
223
224            cl_assert(!sequenceDists);
225            sequenceDists = new LeafRelations;
226
227            SortedPairValues::const_reverse_iterator pair_end = pairsByBranchDistance.rend();
228            for (SortedPairValues::const_reverse_iterator pair = pairsByBranchDistance.rbegin(); pair != pair_end; ++pair) {
229                AP_FLOAT realDist = get_seqDist(pair->get_pair());
230
231                if (realDist>worstDistanceSeen) {
232                    worstDistanceSeen = realDist;
233
234                    delete worstKnownDistance;
235                    worstKnownDistance = new TwoLeafs(pair->get_pair());
236
237                    if (realDist>maxDistance) {     // big distance found -> not a cluster
238                        state = CS_NO_CLUSTER;
239                        break;
240                    }
241                }
242            }
243
244#if defined(TRACE_DIST_CALC)
245            calculatedDistances += sequenceDists->size();
246#endif // TRACE_DIST_CALC
247
248            if (state == CS_IS_CLUSTER) {
249#if defined(DEBUG)
250                // test whether all distances have been calculated
251                cl_assert(!is_leaf);
252                size_t knownDistances = sequenceDists->size() +
253                    get_leftson()->known_seqDists() +
254                    get_rightson()->known_seqDists();
255
256                cl_assert(knownDistances == possible_relations());
257#endif // DEBUG
258
259                get_leftson()->state  = CS_SUB_CLUSTER;
260                get_rightson()->state = CS_SUB_CLUSTER;
261            }
262
263        }
264
265        cl_assert(state == CS_NO_CLUSTER || state == CS_IS_CLUSTER); // detection failure
266
267        lson->oblivion(false);
268        rson->oblivion(false);
269
270        progress.inc();
271        if (progress.aborted()) throw "aborted on userrequest";
272    }
273
274    cl_assert(state != CS_MAYBE_CLUSTER);
275}
276
277void ClusterTree::oblivion(bool forgetDistances) {
278    delete branchDepths;
279    branchDepths = NULL;
280
281    delete branchDists;
282    branchDists = NULL;
283
284    if (state == CS_NO_CLUSTER) {
285        if (forgetDistances) {
286            delete sequenceDists;
287            sequenceDists = NULL;
288        }
289        forgetDistances = true;
290    }
291    else {
292        cl_assert(state & (CS_IS_CLUSTER|CS_SUB_CLUSTER|CS_TOO_SMALL));
293    }
294
295    if (!is_leaf) {
296        get_leftson()->oblivion(forgetDistances);
297        get_rightson()->oblivion(forgetDistances);
298    }
299}
300
301void ClusterTree::calc_branch_depths() {
302    cl_assert(!branchDepths);
303    branchDepths = new NodeValues;
304    if (is_leaf) {
305        (*branchDepths)[this] = 0.0;
306    }
307    else {
308        for (int s = 0; s<2; s++) {
309            const NodeValues *sonDepths = s ? get_leftson()->get_branch_depths() : get_rightson()->get_branch_depths();
310            AP_FLOAT          lenToSon  = s ? leftlen : rightlen;
311
312            NodeValues::const_iterator sd_end = sonDepths->end();
313            for (NodeValues::const_iterator sd = sonDepths->begin(); sd != sd_end; ++sd) {
314                (*branchDepths)[sd->first] = sd->second+lenToSon;
315            }
316        }
317    }
318}
319
320void ClusterTree::calc_branch_dists() {
321    cl_assert(!branchDists);
322    if (!is_leaf) {
323        branchDists = new LeafRelations;
324
325        for (int s = 0; s<2; s++) {
326            ClusterTree         *son      = s ? get_leftson() : get_rightson();
327            const LeafRelations *sonDists = son->get_branch_dists();
328
329            cl_assert(sonDists || son->is_leaf);
330            if (sonDists) branchDists->insert(sonDists->begin(), sonDists->end());
331        }
332
333        const NodeValues *ldepths = get_leftson()->get_branch_depths();
334        const NodeValues *rdepths = get_rightson()->get_branch_depths();
335
336        NodeValues::const_iterator l_end = ldepths->end();
337        NodeValues::const_iterator r_end = rdepths->end();
338
339        for (NodeValues::const_iterator ld = ldepths->begin(); ld != l_end; ++ld) {
340            AP_FLOAT llen = ld->second+leftlen;
341            for (NodeValues::const_iterator rd = rdepths->begin(); rd != r_end; ++rd) {
342                AP_FLOAT rlen = rd->second+rightlen;
343
344                (*branchDists)[TwoLeafs(ld->first, rd->first)] = llen+rlen;
345            }
346        }
347
348        cl_assert(branchDists->size() == possible_relations());
349    }
350}
351
352AP_FLOAT ClusterTree::get_seqDist(const TwoLeafs& pair) {
353    // searches or calculates the distance between the sequences of leafs in 'pair'
354
355    const AP_FLOAT *found = has_seqDist(pair);
356    if (!found) {
357        const ClusterTree *commonFather = pair.first()->commonFatherWith(pair.second());
358
359        while (commonFather != this) {
360            found = commonFather->has_seqDist(pair);
361            if (found) break;
362
363            commonFather = commonFather->get_father();
364            cl_assert(commonFather); // first commonFather was not inside this!
365        }
366    }
367
368    if (!found) {
369        // calculate the distance
370
371        const AP_sequence *seq1 = pair.first()->get_seq();
372        const AP_sequence *seq2 = pair.second()->get_seq();
373
374        seq1->lazy_load_sequence();
375        seq2->lazy_load_sequence();
376
377        {
378            AP_sequence *ancestor     = seq1->dup();
379            AP_FLOAT     mutations    = ancestor->combine(seq1, seq2);
380            AP_FLOAT     wbc1         = seq1->weighted_base_count();
381            AP_FLOAT     wbc2         = seq2->weighted_base_count();
382            AP_FLOAT     minBaseCount = wbc1 < wbc2 ? wbc1 : wbc2;
383            AP_FLOAT     dist;
384
385            if (minBaseCount>0) {
386                dist = mutations / minBaseCount;
387                if (minBaseCount < min_bases) min_bases = minBaseCount;
388            }
389            else { // got at least one empty sequence -> no distance
390                dist      = 0.0;
391                min_bases = minBaseCount;
392            }
393
394#if defined(DEBUG) && 0
395            const char *name1 = pair.first()->name;
396            const char *name2 = pair.second()->name;
397            printf("%s <-?-> %s: mutations=%5.2f wbc1=%5.2f wbc2=%5.2f mbc=%5.2f dist=%5.2f\n",
398                   name1, name2, mutations, wbc1, wbc2, minBaseCount, dist);
399#endif // DEBUG
400
401            cl_assert(!isnan(dist));
402           
403            (*sequenceDists)[pair] = dist;
404            delete ancestor;
405        }
406
407        found = has_seqDist(pair);
408        cl_assert(found);
409    }
410
411    cl_assert(found);
412    return *found;
413}
414
415const AP_FLOAT *ClusterTree::has_seqDist(const TwoLeafs& pair) const {
416    if (sequenceDists) {
417        LeafRelationCIter found = sequenceDists->find(pair);
418        if (found != sequenceDists->end()) {
419            return &(found->second);
420        }
421    }
422    return NULL;
423}
424
425const ClusterTree *ClusterTree::commonFatherWith(const ClusterTree *other) const {
426    int depth_diff = get_depth() - other->get_depth();
427    if (depth_diff) {
428        if (depth_diff<0) { // this is less deep than other
429            return other->get_father()->commonFatherWith(this);
430        }
431        else { // other is less deep than this
432            return get_father()->commonFatherWith(other);
433        }
434    }
435    else { // both at same depth
436        if (this == other) { // common father reached ?
437            return this;
438        }
439        else { // otherwise check fathers
440            return get_father()->commonFatherWith(other->get_father());
441        }
442    }
443}
Note: See TracBrowser for help on using the browser.