root/trunk/CONSENSUS_TREE/CT_ntree.cxx

Revision 8505, 8.0 KB (checked in by westram, 2 months ago)
  • replaced hash+list by set+vector
  • weight parts via ctor
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1// ============================================================= //
2//                                                               //
3//   File      : CT_ntree.cxx                                    //
4//   Purpose   :                                                 //
5//                                                               //
6//   Institute of Microbiology (Technical University Munich)     //
7//   http://www.arb-home.de/                                     //
8//                                                               //
9// ============================================================= //
10
11#include "CT_ntree.hxx"
12#include <arbdbt.h>
13
14// Einen Binaerbaum erzeugen ueber einen Multitree
15
16static NT_NODE *ntree = NULL;
17
18
19const NT_NODE *ntree_get() {
20    // returns the current ntree
21    return ntree;
22}
23
24
25static NT_NODE *new_ntnode(PART*& p) {
26    // build a new node and store the partition p in it
27    NT_NODE *= (NT_NODE *) getmem(sizeof(NT_NODE));
28    n->part     = p;
29    n->son_list = NULL;
30
31    p = NULL;
32    return n;
33}
34
35
36static void del_tree(NT_NODE *tree) {
37    // delete the tree
38    if (tree) {
39        for (NSONS *nsonp = tree->son_list; nsonp;) {
40            NSONS *nson_next = nsonp->next;
41            del_tree(nsonp->node);
42            free(nsonp);
43            nsonp = nson_next;
44        }
45        tree->son_list = NULL;
46
47        // now is leaf
48        delete tree->part;
49        tree->part = NULL;
50        freenull(tree);
51    }
52}
53
54
55void ntree_init(const PartitionSize *registry) {
56    // Initialization of the tree
57    arb_assert(!ntree);              // forgot to call ntree_cleanup ?
58    PART *root = registry->create_root();
59    ntree      = new_ntnode(root); // Set root to completely filled partition
60}
61
62void ntree_cleanup() {
63    // Destruct old tree
64    del_tree(ntree);
65    ntree = NULL;
66}
67
68#if 0
69// test if the tree is already complete (all necessary partitions are inserted)
70static int ntree_cont(int len)
71{
72    return (ntree_count<len);
73}
74#endif
75
76int ntree_count_sons(const NT_NODE *tree) {
77    int sons = 0;
78    if (tree->son_list) {
79        for (NSONS *node = tree->son_list; node; node = node->next) {
80            sons++;
81        }
82    }
83    return sons;
84}
85
86static void move_son(NT_NODE *f_node, NT_NODE *s_node, NSONS *nson) {
87    // Move son from parent-sonlist to new sonlist
88    // nson is pointer on element in parent-sonlist
89    // sonlist is new sonlist where to move in
90
91    // Move out of parent-sonlist
92   
93    if (nson == f_node->son_list) f_node->son_list = f_node->son_list->next;
94    if (nson->prev) nson->prev->next = nson->next;
95    if (nson->next) nson->next->prev = nson->prev;
96
97    // Move in node-sonlist
98    nson->next = s_node->son_list;
99    nson->prev = NULL;
100   
101    if (s_node->son_list) s_node->son_list->prev = nson;
102    s_node->son_list                             = nson;
103}
104
105
106
107static int ins_ntree(NT_NODE *tree, PART*& newpart) {
108    /* Construct a multitree under the constraint,
109     * that the final tree may result in a binary tree.
110     *
111     * To ensure this, it is important to follow two ideas:
112     *
113     * 1. a son only fits below a father
114     *    - if the father has all son-bits set AND
115     *    - the father is different from the son (so it is possible to add a brother)
116     *
117     * 2. brothers are distinct (i.e. they do not share any bits)
118     */
119
120    // Tree is leaf
121    if (!tree->son_list) {
122#if defined(DUMP_PART_INSERTION)
123        fputs("ins_ntree part=", stdout); newpart->print();
124#endif
125
126        tree->son_list       = (NSONS *) getmem(sizeof(NSONS));
127        tree->son_list->node = new_ntnode(newpart);
128
129        return 1;
130    }
131
132    // test if part fit under one son of tree -> recursion
133    for (NSONS *nsonp = tree->son_list; nsonp; nsonp=nsonp->next) {
134        if (newpart->is_son_of(nsonp->node->part)) {
135            int res = ins_ntree(nsonp->node, newpart);
136            arb_assert(contradicted(newpart, res));
137            return res;
138        }
139    }
140
141    // If partition is not a son maybe it is a brother
142    // If it is neither brother nor son -> don't fit here
143    for (NSONS *nsonp = tree->son_list; nsonp; nsonp=nsonp->next) {
144        if (nsonp->node->part->overlaps_with(newpart)) {
145            if (!nsonp->node->part->is_son_of(newpart)) {
146                arb_assert(newpart);
147                return 0;
148            }
149            // accept if nsonp is son of newpart (will be pulled down below)
150        }
151    }
152
153#if defined(DUMP_PART_INSERTION)
154        fputs("ins_ntree part=", stdout); newpart->print();
155#endif
156
157    // Okay, insert part here ...
158    NT_NODE *newntnode = new_ntnode(newpart);
159
160    // Move sons from parent-sonlist into the new sons sonlist
161    {
162        NSONS *nsonp = tree->son_list;
163        while (nsonp) {
164            NSONS *nsonp_next = nsonp->next;
165            if (nsonp->node->part->is_son_of(newntnode->part)) {
166                move_son(tree, newntnode, nsonp);
167            }
168            nsonp = nsonp_next;
169        }
170    }
171
172    // insert nsons-elem in son-list of father
173    {
174        NSONS *new_son = (NSONS *) getmem(sizeof(NSONS));
175   
176        new_son->node = newntnode;
177        new_son->prev = NULL;
178        new_son->next = tree->son_list;
179
180        if (tree->son_list) tree->son_list->prev = new_son;
181        tree->son_list                           = new_son;
182    }
183
184    arb_assert(!newpart);
185
186    return 1;
187}
188
189
190
191void insert_ntree(PART*& part) {
192    /* Insert a partition in the NTree.
193     *
194     * Tries both representations, normal and inverse partition,  which
195     * represent the two subtrees at both sides of one edge.
196     *
197     * If neither can be inserted, the partition gets dropped.
198     */
199
200    arb_assert(part->is_valid());
201
202    bool firstCall = ntree->son_list == NULL;
203    if (firstCall) {
204        part->set_len(part->get_len()/2); // insert as root-edge -> distribute length
205
206        PART *inverse = part->clone();
207        inverse->invert();
208
209        ASSERT_RESULT(bool, true, ins_ntree(ntree, part));
210        ASSERT_RESULT(bool, true, ins_ntree(ntree, inverse));
211
212        arb_assert(!inverse);
213    }
214    else {
215        if (!ins_ntree(ntree, part)) {
216            part->invert();
217            if (!ins_ntree(ntree, part)) {
218                delete part; // drop non-fitting partition
219                part = NULL;
220            }
221        }
222    }
223    arb_assert(!part);
224}
225
226// --------------------------------------------------------------------------------
227
228#if defined(NTREE_DEBUG_FUNCTIONS)
229
230inline void do_indent(int indent) {
231    for (int i = 0; i<indent; ++i) fputc(' ', stdout);
232}
233
234void print_ntree(NT_NODE *tree, int indent) {
235    // testfunction to print a NTree
236
237    NSONS *nsonp;
238    if (tree == NULL) {
239        do_indent(indent); 
240        fputs("tree is empty\n", stdout);
241        return;
242    }
243
244    // print father
245    do_indent(indent);
246    fputs("(\n", stdout);
247
248    indent++;
249
250    do_indent(indent);
251    tree->part->print();
252
253    // and sons
254    for (nsonp=tree->son_list; nsonp; nsonp = nsonp->next) {
255        print_ntree(nsonp->node, indent);
256    }
257
258    indent--;
259   
260    do_indent(indent);
261    fputs(")\n", stdout);
262}
263
264bool is_well_formed(const NT_NODE *tree) {
265    // checks whether
266    // - tree has sons
267    // - all sons are part of father
268    // - all sons are distinct
269    // - father is sum of sons
270
271    int sons = ntree_count_sons(tree);
272
273    if (!sons) return tree->part->get_members() == 1; // leafs should contain single species
274
275    bool well_formed = true;
276
277    arb_assert(tree->son_list);
278   
279    PART *pmerge = 0;
280    for (NSONS *nson = tree->son_list; nson; nson = nson->next) {
281        PART *pson = nson->node->part;
282
283        if (!pson->is_son_of(tree->part)) {
284            well_formed = false;
285        }
286        if (pmerge) {
287            if (pson->overlaps_with(pmerge)) {
288                well_formed  = false;
289            }
290            pmerge->add_from(pson);
291        }
292        else {
293            pmerge = pson->clone();
294        }
295        if (!is_well_formed(nson->node)) {
296            well_formed = false;
297            is_well_formed(nson->node);
298        }
299    }
300    arb_assert(pmerge);
301    if (tree->part->differs(pmerge)) {
302        well_formed = false;
303    }
304    delete pmerge;
305
306    return well_formed;
307}
308
309#endif
Note: See TracBrowser for help on using the browser.