root/trunk/CONSENSUS_TREE/CT_part.cxx

Revision 8507, 9.8 KB (checked in by westram, 2 months ago)
  • use double for weights ([0..1] instead of [0..10000])
  • added tests using weights != 1
    • fixed weight/length calculation to make generated consense tree independent from used weight (as long as the same weight is used for all added trees)
  • no longer generates zero-bootstrap at root
    • strictly speaking it is wrong now (since the edge from virtual root to tree cant exist, ergo it's probability should be zero)
    • practically
      • that zero probability would be a special case (and is an error at all other edges)
      • a probability of 100% is used (which gets skipped when saving the tree)
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1// ============================================================= //
2//                                                               //
3//   File      : CT_part.cxx                                     //
4//   Purpose   :                                                 //
5//                                                               //
6//   Institute of Microbiology (Technical University Munich)     //
7//   http://www.arb-home.de/                                     //
8//                                                               //
9// ============================================================= //
10
11/* This module is designed to organize the data structure partitions
12   partitions represent the edges of a tree */
13// the partitions are implemented as an array of longs
14// Each leaf in a GBT-Tree is represented as one Bit in the Partition
15
16#include "CT_part.hxx"
17#include <arbdbt.h>
18
19#if defined(DEBUG)
20#endif
21
22#define BITS_PER_PELEM (sizeof(PELEM)*8)
23
24#if defined(DUMP_PART_INIT) || defined(UNIT_TESTS)
25static const char *readable_cutmask(PELEM mask) {
26    static char readable[BITS_PER_PELEM+1];
27    memset(readable, '0', BITS_PER_PELEM);
28    readable[BITS_PER_PELEM]        = 0;
29
30    for (int b = BITS_PER_PELEM-1; b >= 0; --b) {
31        if (mask&1) readable[b] = '1';
32        mask = mask>>1;
33    }
34    return readable;
35}
36#endif
37
38PartitionSize::PartitionSize(const int len)
39    : cutmask(0),
40      longs((((len + 7) / 8)+sizeof(PELEM)-1) / sizeof(PELEM)),
41      bits(len),
42      id(0)
43{
44    /*! Function to initialize the global variables above
45     * @param len number of bits the part should content
46     *
47     * result: calculate cutmask, longs, plen
48     */
49
50    int j      = len % BITS_PER_PELEM;
51    if (!j) j += BITS_PER_PELEM;
52
53    for (int i=0; i<j; i++) {
54        cutmask <<= 1;
55        cutmask |= 1;
56    }
57
58#if defined(DEBUG)
59    size_t possible = longs*BITS_PER_PELEM;
60    arb_assert((possible-bits)<BITS_PER_PELEM); // longs is too big (wasted space)
61
62#if defined(DUMP_PART_INIT)
63    printf("leafs=%i\n", len);
64    printf("cutmask='%s'\n", readable_cutmask(cutmask));
65    printf("longs=%i (can hold %zu bits)\n", longs, possible);
66    printf("bits=%i\n", bits);
67#endif
68#endif
69}
70
71#if defined(NTREE_DEBUG_FUNCTIONS)
72void PART::print() const {
73    // ! Testfunction to print a part
74    int i, j, k=0;
75    PELEM l;
76
77    int longs = get_longs();
78    int plen = info->get_bits();
79    for (i=0; i<longs; i++) {
80        l = 1;
81        for (j=0; k<plen && size_t(j)<sizeof(PELEM)*8; j++, k++) {
82            if (p[i] & l)
83                printf("1");
84            else
85                printf("0");
86            l <<= 1;
87        }
88    }
89
90    printf("  len=%.5f  prob=%5.1f%%  leaf=%i  dist2center=%i\n", len, weight*100.0, is_leaf_edge(), distance_to_tree_center());
91}
92#endif
93
94PART *PartitionSize::create_root() const {
95    /*! build a partition that totally consists of 111111...1111 that is needed to
96     * build the root of a specific ntree
97     */
98
99    PART *p = new PART(this, 1.0);
100    p->invert();
101    arb_assert(p->is_valid());
102    return p;
103}
104
105
106bool PART::is_son_of(const PART *father) const {
107    /*! test if the part 'son' is possibly a son of the part 'father'.
108     *
109     * A father defined in this context as a part covers every bit of his son. needed in CT_ntree
110     */
111
112    arb_assert(is_valid());
113    arb_assert(father->is_valid());
114   
115    bool is_equal = true;
116    int longs = get_longs();
117    for (int i=0; i<longs; i++) {
118        PELEM s = p[i];
119        PELEM f = father->p[i];
120
121        if ((s&f) != s) return false; // father has not all son bits set
122        if (s != f) is_equal = false;
123    }
124
125    arb_assert(!is_equal); // if is_equal, father and son are identical (which is wrong);
126                           // e.g. happens when PartRegistry stores multiple instances of the same part
127    return true;
128}
129
130
131bool PART::overlaps_with(const PART *other) const {
132    /*! test if two parts overlap (i.e. share common bits)
133     */
134
135    arb_assert(is_valid());
136    arb_assert(other->is_valid());
137
138    int longs = get_longs();
139    for (int i=0; i<longs; i++) {
140        if (p[i] & other->p[i]) return true;
141    }
142    return false;
143}
144
145void PART::invert() {
146    //! invert a part
147    //
148    // Each edge in a tree connects two subtrees.
149    // These subtrees are represented by inverse partitions
150
151    arb_assert(is_valid());
152   
153    int longs = get_longs();
154    for (int i=0; i<longs; i++) {
155        p[i] = ~p[i];
156    }
157    p[longs-1] &= get_cutmask();
158
159    members = get_maxsize()-members;
160
161    arb_assert(is_valid());
162}
163
164void PART::add_from(const PART *source) {
165    //! destination = source or destination
166    arb_assert(source->is_valid());
167    arb_assert(is_valid());
168
169    bool distinct = disjunct_from(source);
170
171    int longs = get_longs();
172    for (int i=0; i<longs; i++) {
173        p[i] |= source->p[i];
174    }
175
176    if (distinct) {
177        members += source->members;
178    }
179    else {
180        members = count_members();
181    }
182
183    arb_assert(is_valid());
184}
185
186
187bool PART::equals(const PART *other) const {
188    /*! return true if p1 and p2 are equal
189     */
190    arb_assert(is_valid());
191    arb_assert(other->is_valid());
192
193    int longs = get_longs();
194    for (int i=0; i<longs; i++) {
195        if (p[i] != other->p[i]) return false;
196    }
197    return true;
198}
199
200
201unsigned PART::key() const {
202    //! calculate a hashkey from part
203    arb_assert(is_valid());
204
205    PELEM ph = 0;
206    int longs = get_longs();
207    for (int i=0; i<longs; i++) {
208        ph ^= p[i];
209    }
210 
211    return ph;
212}
213
214int PART::count_members() const { 
215    //! count the number of leafs in partition
216    int leafs = 0;
217    int longs = get_longs();
218    for (int i = 0; i<longs; ++i) {
219        PELEM e = p[i];
220
221        if (i == (longs-1)) e = e&get_cutmask();
222
223        for (size_t b = 0; b<(sizeof(e)*8); ++b) {
224            if (e&1) leafs++;
225            e = e>>1;
226        }
227    }
228    return leafs;
229}
230
231bool PART::is_standardized() const { // @@@ inline
232    return p[0] & 1;
233}
234
235void PART::standardize() { // @@@ inline or elim
236    /*! standardize the partition
237     *
238     * two parts are equal if one is just the inverted version of the other.
239     * so the standard is defined that the version is the representant, whose first bit is equal 1
240     */
241    arb_assert(is_valid());
242    if (!is_standardized()) invert();
243    arb_assert(is_valid());
244}
245
246int PART::index() const {
247    /*! calculate the first bit set in p,
248     *
249     * this is only useful if only one bit is set,
250     * this is used to identify leafs in a ntree
251     *
252     * ATTENTION: p must be != NULL
253     */
254    arb_assert(is_valid());
255    arb_assert(is_leaf_edge());
256
257    int pos   = 0;
258    int longs = get_longs();
259    for (int i=0; i<longs; i++) {
260        PELEM p_temp = p[i];
261        pos = i * sizeof(PELEM) * 8;
262        if (p_temp) {
263            for (; p_temp; p_temp >>= 1, pos++) {
264                ;
265            }
266            break;
267        }
268    }
269    return pos-1;
270}
271
272int PART::insertionOrder_cmp(const PART *other) const {
273    // defines order in which edges will be inserted into the consensus tree
274
275    if (this == other) return 0;
276
277    int cmp = is_leaf_edge() - other->is_leaf_edge();
278
279    if (!cmp) {
280        cmp = double_cmp(weight, other->weight); // insert bigger weight first
281        if (!cmp) {
282            int centerdist1 = distance_to_tree_center();
283            int centerdist2 = other->distance_to_tree_center();
284
285            cmp = centerdist1-centerdist2; // insert central edges first
286
287            if (!cmp) {
288                cmp = double_cmp(other->get_len(), get_len()); // insert bigger len first
289                if (!cmp) {
290                    cmp = id - other->id; // strict by definition
291                    arb_assert(cmp);
292                }
293            }
294        }
295    }
296
297    return cmp;
298}
299inline int PELEM_cmp(const PELEM& p1, const PELEM& p2) {
300    return p1<p2 ? -1 : (p1>p2 ? 1 : 0);
301}
302
303int PART::topological_cmp(const PART *other) const {
304    // define a strict order on topologies defined by edges
305   
306    if (this == other) return 0;
307
308    arb_assert(is_standardized());
309    arb_assert(other->is_standardized());
310
311    int cmp = members - other->members;
312    if (!cmp) {
313        int longs = get_longs();
314        for (int i = 0; !cmp && i<longs; ++i) {
315            cmp = PELEM_cmp(p[i], other->p[i]);
316        }
317    }
318
319    arb_assert(contradicted(cmp, equals(other)));
320
321    return cmp;
322}
323
324
325// --------------------------------------------------------------------------------
326
327#ifdef UNIT_TESTS
328#ifndef TEST_UNIT_H
329#include <test_unit.h>
330#endif
331
332void TEST_PartRegistry() {
333    {
334        PartitionSize reg(0);
335        TEST_ASSERT_EQUAL(reg.get_bits(), 0);
336        TEST_ASSERT_EQUAL(reg.get_longs(), 0);
337        // cutmask doesnt matter
338    }
339
340    {
341        PartitionSize reg(1);
342        TEST_ASSERT_EQUAL(reg.get_bits(), 1);
343        TEST_ASSERT_EQUAL(reg.get_longs(), 1);
344        TEST_ASSERT_EQUAL(readable_cutmask(reg.get_cutmask()), "00000000000000000000000000000001");
345    }
346
347    {
348        PartitionSize reg(31);
349        TEST_ASSERT_EQUAL(reg.get_bits(), 31);
350        TEST_ASSERT_EQUAL(reg.get_longs(), 1);
351        TEST_ASSERT_EQUAL(readable_cutmask(reg.get_cutmask()), "01111111111111111111111111111111");
352    }
353
354    {
355        PartitionSize reg(32);
356        TEST_ASSERT_EQUAL(reg.get_bits(), 32);
357        TEST_ASSERT_EQUAL(reg.get_longs(), 1);
358        TEST_ASSERT_EQUAL(readable_cutmask(reg.get_cutmask()), "11111111111111111111111111111111");
359    }
360
361    {
362        PartitionSize reg(33);
363        TEST_ASSERT_EQUAL(reg.get_bits(), 33);
364        TEST_ASSERT_EQUAL(reg.get_longs(), 2);
365        TEST_ASSERT_EQUAL(readable_cutmask(reg.get_cutmask()), "00000000000000000000000000000001");
366    }
367
368    {
369        PartitionSize reg(95);
370        TEST_ASSERT_EQUAL(reg.get_bits(), 95);
371        TEST_ASSERT_EQUAL(reg.get_longs(), 3);
372        TEST_ASSERT_EQUAL(readable_cutmask(reg.get_cutmask()), "01111111111111111111111111111111");
373    }
374}
375
376#endif // UNIT_TESTS
377
378// --------------------------------------------------------------------------------
379
Note: See TracBrowser for help on using the browser.