source: branches/items/PROBE_SET/ps_detect_weak_differences.cxx

Last change on this file was 18730, checked in by westram, 3 years ago
  • remove trailing whitespace from c source.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.5 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : ps_detect_weak_differences.cxx                    //
4//   Purpose   :                                                   //
5//                                                                 //
6//   Coded by Wolfram Foerster in October 2002                     //
7//   Institute of Microbiology (Technical University Munich)       //
8//   http://www.arb-home.de/                                       //
9//                                                                 //
10// =============================================================== //
11
12#include "ps_database.hxx"
13#include "ps_bitmap.hxx"
14#include "ps_tools.hxx"
15
16#include <climits>
17#include <sys/times.h>
18
19// common globals
20static SpeciesID          __MAX_ID;
21static SpeciesID          __MIN_ID;
22static PS_BitMap_Fast    *__MAP;
23// globals for PS_detect_weak_differences
24static IDVector          *__PATH;
25static IDVector          *__INVERSE_PATH;
26static unsigned long int  __COUNT_SET_OPS  = 0;
27static unsigned long int  __COUNT_SET_OPS2 = 0;
28static char              *__NODES_LEFT;
29// globals for PS_print_and_evaluate_map
30static IDSet             *__PATHSET;
31static IDID2IDSetMap     *__PAIR2PATH;
32static SpeciesID          __ONEMATCH_MIN_ID;
33static SpeciesID          __ONEMATCH_MAX_ID;
34
35#if defined(DEBUG)
36void PS_debug_print_path() {
37    printf("__PATH %3zu :", __PATH->size());
38    int c = 1;
39    for (IDVectorCIter i = __PATH->begin(); i != __PATH->end(); ++i, ++c) {
40        if (c % 20 == 0) printf("\n");
41        printf(" %3i", *i);
42    }
43    printf("\n");
44}
45
46void PS_debug_print_inverse_path() {
47    printf("__INVERSE_PATH %3zu :", __INVERSE_PATH->size());
48    int c = 1;
49    for (IDVectorCIter i = __INVERSE_PATH->begin(); i != __INVERSE_PATH->end(); ++i, ++c) {
50        if (c % 20 == 0) printf("\n");
51        printf(" %3i", *i);
52    }
53    printf("\n");
54}
55#endif
56
57static void PS_detect_weak_differences_stepdown(const PS_NodePtr& _ps_node,
58                                                const SpeciesID  _parent_ID,
59                                                const long       _depth) {
60    //  Recursively walk through tree and make a bool-matrix of SpeciesID's
61    //  where true means that the 2 species can be distinguished by a probe.
62    //
63    //  The first occurrence of a pair of distinguishable IDs is stored as (smaller_ID,bigger_ID).
64    //  The following occurrence of this pair are stored as (bigger_ID,smaller_ID).
65    //  (this allows us to find pairs of SpeciesIDs that can be distinguished by exactly one probe)
66
67    SpeciesID id = _ps_node->getNum();
68    if (_depth < 60) {
69        printf("%s", __NODES_LEFT);
70        for (int i = 0; i < 60; ++i) printf("\b");
71        fflush(stdout);
72    }
73    //
74    // append IDs to paths
75    //
76    __PATH->push_back(id);                                                                      // append id to path
77    for (SpeciesID i = (_parent_ID < __MIN_ID) ? __MIN_ID : _parent_ID+1; i < id; ++i) {        // append parent_id+1 .. id-1 to inverse path
78        __INVERSE_PATH->push_back(i);
79    }
80
81    //
82    // set values in the maps if node has probes
83    //
84    if (_ps_node->hasProbes()) {
85        if (_ps_node->hasPositiveProbes() && _ps_node->hasInverseProbes()) {
86            unsigned long int set_ops = 2*__PATH->size()*(__MAX_ID-id-1+__INVERSE_PATH->size());
87            if (ULONG_MAX - __COUNT_SET_OPS < set_ops) {
88                set_ops = set_ops - (ULONG_MAX - __COUNT_SET_OPS);
89                __COUNT_SET_OPS = 0;
90                ++__COUNT_SET_OPS2;
91            }
92            __COUNT_SET_OPS = __COUNT_SET_OPS + set_ops;
93
94            SpeciesID inverse_path_ID;
95            // path loop
96            for (IDVectorCIter it_path = __PATH->begin();
97                 it_path != __PATH->end();
98                 ++it_path) {
99                SpeciesID path_ID = *it_path;
100                // inverse path loop (explicit)
101                for (IDVectorCIter it_inverse_path = __INVERSE_PATH->begin();
102                     it_inverse_path != __INVERSE_PATH->end();
103                     ++it_inverse_path) {
104                    inverse_path_ID = *it_inverse_path;
105
106                    __MAP->setTrue(path_ID, inverse_path_ID);
107                    __MAP->setTrue(inverse_path_ID, path_ID);
108                }
109
110                // inverse path loop (implicit)
111                for (inverse_path_ID = id+1; inverse_path_ID < __MAX_ID; ++inverse_path_ID) { // skip to id ABOVE current node id
112                    __MAP->setTrue(path_ID, inverse_path_ID);
113                    __MAP->setTrue(inverse_path_ID, path_ID);
114                }
115            }
116        }
117        else {
118            unsigned long int set_ops = __PATH->size()*(__MAX_ID-id-1+__INVERSE_PATH->size());
119            if (ULONG_MAX - __COUNT_SET_OPS < set_ops) {
120                set_ops = set_ops - (ULONG_MAX - __COUNT_SET_OPS);
121                __COUNT_SET_OPS = 0;
122                ++__COUNT_SET_OPS2;
123            }
124            __COUNT_SET_OPS = __COUNT_SET_OPS + set_ops;
125
126            SpeciesID inverse_path_ID;
127            SpeciesID smaller_ID;
128            SpeciesID bigger_ID;
129            // path loop
130            for (IDVectorCIter it_path = __PATH->begin();
131                 it_path != __PATH->end();
132                 ++it_path) {
133                SpeciesID path_ID = *it_path;
134                // inverse path loop (explicit)
135                for (IDVectorCIter it_inverse_path = __INVERSE_PATH->begin();
136                     it_inverse_path != __INVERSE_PATH->end();
137                     ++it_inverse_path) {
138                    inverse_path_ID = *it_inverse_path;
139                    smaller_ID = (path_ID < inverse_path_ID) ? path_ID : inverse_path_ID;
140                    bigger_ID  = (path_ID > inverse_path_ID) ? path_ID : inverse_path_ID;
141
142                    if (__MAP->get(smaller_ID, bigger_ID)) {
143                        __MAP->setTrue(bigger_ID, smaller_ID);
144                    }
145                    else {
146                        __MAP->setTrue(smaller_ID, bigger_ID);
147                    }
148                }
149
150                // inverse path loop (implicit)
151                for (inverse_path_ID = id+1; inverse_path_ID < __MAX_ID; ++inverse_path_ID) { // skip to id ABOVE current node id
152                    smaller_ID = (path_ID < inverse_path_ID) ? path_ID : inverse_path_ID;
153                    bigger_ID  = (path_ID > inverse_path_ID) ? path_ID : inverse_path_ID;
154
155                    if (__MAP->get(smaller_ID, bigger_ID)) {
156                        __MAP->setTrue(bigger_ID, smaller_ID);
157                    }
158                    else {
159                        __MAP->setTrue(smaller_ID, bigger_ID);
160                    }
161                }
162            }
163        }
164    }
165    //
166    // step down the children
167    //
168    int c = _ps_node->countChildren()-1;
169    for (PS_NodeMapConstIterator i = _ps_node->getChildrenBegin();
170          i != _ps_node->getChildrenEnd();
171          ++i, --c) {
172        if (_depth < 60) {
173            if (c < 10) {
174                __NODES_LEFT[_depth] = '0'+c;
175            }
176            else {
177                __NODES_LEFT[_depth] = '+';
178            }
179        }
180        PS_detect_weak_differences_stepdown(i->second, id, _depth+1);
181    }
182    if (_depth < 60) __NODES_LEFT[_depth] = ' ';
183
184    //
185    // remove IDs from paths
186    //
187    __PATH->pop_back();
188    while ((__INVERSE_PATH->back() > _parent_ID) && (!__INVERSE_PATH->empty())) {
189        __INVERSE_PATH->pop_back();
190    }
191}
192
193static void PS_detect_weak_differences(const PS_NodePtr& _root_node) {
194    //
195    // make bitmap
196    //
197    __PATH         = new IDVector;
198    __INVERSE_PATH = new IDVector;
199
200    int c = 0;
201    struct tms before;
202    times(&before);
203    struct tms before_first_level_node;
204    for (PS_NodeMapConstIterator i = _root_node->getChildrenBegin(); i != _root_node->getChildrenEnd(); ++i, ++c) {
205        if (_root_node->countChildren()-c-1 < 10) {
206            __NODES_LEFT[0] = '0'+_root_node->countChildren()-c-1;
207        }
208        else {
209            __NODES_LEFT[0] = '+';
210        }
211        if ((c < 50) || (c % 100 == 0)) {
212            times(&before_first_level_node);
213            printf("PS_detect_weak_differences_stepdown( %i ) : %i. of %zu  ", i->first, c+1, _root_node->countChildren()); fflush(stdout);
214        }
215        PS_detect_weak_differences_stepdown(i->second, -1, 1);
216        if ((c < 50) || (c % 100 == 0)) {
217            PS_print_time_diff(&before_first_level_node, "this node ", "  ");
218            PS_print_time_diff(&before, "total ", "\n");
219        }
220    }
221    printf("%lu * %lu + %lu set operations performed\n", __COUNT_SET_OPS2, ULONG_MAX, __COUNT_SET_OPS); fflush(stdout);
222
223    delete __PATH;
224    delete __INVERSE_PATH;
225}
226
227typedef map<ID2IDPair, PS_NodePtr>    IDID2NodeMap;
228typedef IDID2NodeMap::iterator       IDID2NodeMapIter;
229typedef IDID2NodeMap::const_iterator IDID2NodeMapCIter;
230
231void PS_find_probes_for_pairs(const PS_NodePtr& _ps_node, ID2IDSet &_pairs) {
232    SpeciesID id         = _ps_node->getNum();
233    bool      has_probes = _ps_node->hasProbes();
234
235    //
236    // append ID to path
237    //
238    __PATHSET->insert(id);
239
240    //
241    // don't look at path until ID is greater than lowest ID in the set of ID-pairs
242    //
243    if ((id >= __ONEMATCH_MIN_ID) && has_probes) {
244        for (ID2IDSetCIter pair=_pairs.begin(); pair != _pairs.end(); ++pair) {
245            // look for pair-IDs in the path
246            bool found_first  = __PATHSET->find(pair->first) != __PATHSET->end();
247            bool found_second = __PATHSET->find(pair->second) != __PATHSET->end();
248            if (found_first ^ found_second) { // ^ is XOR
249                printf("found path for (%i,%i) at %p ", pair->first, pair->second, &(*_ps_node));
250                _ps_node->printOnlyMe();
251                (*__PAIR2PATH)[*pair] = *__PATHSET;     // store path
252
253                bool scanMinMax = (pair->first == __ONEMATCH_MIN_ID) || (pair->second == __ONEMATCH_MAX_ID);
254                _pairs.erase(pair);                     // remove found pair
255                if (scanMinMax) {
256                    // scan pairs for new min,max IDs
257                    __ONEMATCH_MIN_ID = __MAX_ID;
258                    __ONEMATCH_MAX_ID = -1;
259                    for (ID2IDSetCIter p=_pairs.begin(); p != _pairs.end(); ++p) {
260                        if (p->first  < __ONEMATCH_MIN_ID) __ONEMATCH_MIN_ID = p->first;
261                        if (p->second > __ONEMATCH_MAX_ID) __ONEMATCH_MAX_ID = p->second;
262                    }
263                    printf(" new MIN,MAX (%d,%d)", __ONEMATCH_MIN_ID, __ONEMATCH_MAX_ID);
264                }
265                printf("\n");
266            }
267        }
268    }
269
270    //
271    // step down the children unless all paths are found
272    // if either ID is lower than highest ID in the set of ID-pairs
273    // or the node has no probes
274    //
275    if ((id < __ONEMATCH_MAX_ID) || (! has_probes)) {
276        for (PS_NodeMapConstIterator i = _ps_node->getChildrenBegin();
277             (i != _ps_node->getChildrenEnd()) && (!_pairs.empty());
278             ++i) {
279            PS_find_probes_for_pairs(i->second, _pairs);
280        }
281    }
282
283    //
284    // remove ID from path
285    //
286    __PATHSET->erase(id);
287}
288
289static void PS_print_and_evaluate_map(const PS_NodePtr& _root_node, const char *_result_filename) {
290    //
291    // print and evaluate bitmap
292    //
293    printf("\n\n----------------- bitmap ---------------\n\n");
294    SpeciesID smaller_id;
295    SpeciesID bigger_id;
296    ID2IDSet  noMatch;
297    ID2IDSet  oneMatch;
298    bool      bit1;
299    bool      bit2;
300    __ONEMATCH_MIN_ID = __MAX_ID;
301    __ONEMATCH_MAX_ID = __MIN_ID;
302    for (SpeciesID id1 = __MIN_ID; id1 <= __MAX_ID; ++id1) {
303        for (SpeciesID id2 = __MIN_ID; id2 <= id1; ++id2) {
304            smaller_id = (id1 < id2) ? id1 : id2;
305            bigger_id  = (id1 < id2) ? id2 : id1;
306            bit1       = __MAP->get(smaller_id, bigger_id);
307            bit2       = __MAP->get(bigger_id, smaller_id);
308            if (bit1 && bit2) {
309            }
310            else if (bit1) {
311                oneMatch.insert(ID2IDPair(smaller_id, bigger_id));
312                if (smaller_id < __ONEMATCH_MIN_ID) __ONEMATCH_MIN_ID = smaller_id;
313                if (bigger_id  > __ONEMATCH_MAX_ID) __ONEMATCH_MAX_ID = bigger_id;
314            }
315            else {
316                if (id1 != id2) noMatch.insert(ID2IDPair(smaller_id, bigger_id));  // there are no probes to distinguish a species from itself .. obviously
317            }
318        }
319    }
320    printf("(enter to continue)\n");
321
322    printf("\n\n----------------- no matches ---------------\n\n");
323    if (!_result_filename) {
324        for (ID2IDSetCIter i = noMatch.begin(); i != noMatch.end(); ++i) {
325            printf("%6i %6i\n", i->first, i->second);
326        }
327    }
328    printf("%zu no matches\n(enter to continue)\n", noMatch.size());
329
330    printf("\n\n----------------- one match ---------------\n\n");
331    if (!_result_filename) {
332        for (ID2IDSetCIter i = oneMatch.begin(); i != oneMatch.end(); ++i) {
333            printf("%6i %6i\n", i->first, i->second);
334        }
335    }
336    printf("%zu one matches\n(enter to continue)\n", oneMatch.size());
337    //
338    // find paths for pairs
339    //
340    __PATHSET   = new IDSet;
341    __PAIR2PATH = new IDID2IDSetMap;
342    int c = 0;
343    for (PS_NodeMapConstIterator i = _root_node->getChildrenBegin();
344         (i != _root_node->getChildrenEnd()) && (!oneMatch.empty());
345         ++i, ++c) {
346        if ((c < 50) || (c % 100 == 0)) printf("PS_find_probes_for_pairs( %i ) : %i of %zu\n", i->first, c+1, _root_node->countChildren());
347        PS_find_probes_for_pairs(i->second, oneMatch);
348    }
349    //
350    // print paths
351    //
352    for (IDID2IDSetMapCIter i = __PAIR2PATH->begin();
353         i != __PAIR2PATH->end();
354         ++i) {
355        printf("\nPair (%i,%i) Setsize (%zu)", i->first.first, i->first.second, i->second.size());
356        PS_NodePtr current_node = _root_node;
357        long c2 = 0;
358        for (IDSetCIter path_id=i->second.begin();
359             path_id != i->second.end();
360             ++path_id, ++c2) {
361            current_node = current_node->getChild(*path_id).second;
362            if (c2 % 10 == 0) printf("\n");
363            printf("%6i%s ", *path_id, (current_node->hasProbes()) ? ((current_node->hasInverseProbes()) ? "*" : "+") : "-");
364        }
365        printf("\nFinal Node : %p ", &(*current_node));
366        current_node->printOnlyMe();
367        printf("\n");
368    }
369    printf("\n%zu paths\n", __PAIR2PATH->size());
370    //
371    // oups
372    //
373    if (!oneMatch.empty()) {
374        printf("did not find a path for these :\n");
375        for (ID2IDSetCIter i = oneMatch.begin(); i != oneMatch.end(); ++i) {
376            printf("%6i %6i\n", i->first, i->second);
377        }
378    }
379    //
380    // make preset map
381    //
382    PS_BitMap_Counted *preset = new PS_BitMap_Counted(false, __MAX_ID+1);
383    // set bits for no matches
384    for (ID2IDSetCIter pair=noMatch.begin(); pair != noMatch.end(); ++pair) {
385        preset->setTrue(pair->second, pair->first);
386    }
387    // iterate over paths
388    for (IDID2IDSetMapCIter i = __PAIR2PATH->begin();
389         i != __PAIR2PATH->end();
390         ++i) {
391        // iterate over all IDs except path
392        IDSetCIter path_iter    = i->second.begin();
393        SpeciesID  next_path_id = *path_iter;
394        for (SpeciesID id = __MIN_ID; id <= __MAX_ID; ++id) {
395            if (id == next_path_id) {   // if i run into a ID in path
396                ++path_iter;            // advance to next path ID
397                next_path_id = (path_iter == i->second.end()) ? -1 : *path_iter;
398                continue;               // skip this ID
399            }
400            // iterate over path IDs
401            for (IDSetCIter path_id = i->second.begin(); path_id != i->second.end(); ++path_id) {
402                if (id == *path_id) continue;   // obviously a probe cant differ a species from itself
403                if (id > *path_id) {
404                    preset->setTrue(id, *path_id);
405                }
406                else {
407                    preset->setTrue(*path_id, id);
408                }
409            }
410        }
411    }
412    preset->recalcCounters();
413    if (!_result_filename) preset->print(stdout);
414    //
415    // save results
416    //
417    if (_result_filename) {
418        PS_FileBuffer *result_file = new PS_FileBuffer(_result_filename, PS_FileBuffer::WRITEONLY);
419        // no matches
420        printf("saving no matches to %s...\n", _result_filename);
421        result_file->put_long(noMatch.size());
422        for (ID2IDSetCIter i = noMatch.begin(); i != noMatch.end(); ++i) {
423            result_file->put_int(i->first);
424            result_file->put_int(i->second);
425        }
426        // one matches
427        printf("saving one matches to %s...\n", _result_filename);
428        result_file->put_long(__PAIR2PATH->size());
429        for (IDID2IDSetMapCIter i = __PAIR2PATH->begin(); i != __PAIR2PATH->end(); ++i) {
430            result_file->put_int(i->first.first);
431            result_file->put_int(i->first.second);
432            result_file->put_long(i->second.size());
433            for (IDSetCIter path_id=i->second.begin(); path_id != i->second.end(); ++path_id) {
434                result_file->put_int(*path_id);
435            }
436        }
437        // preset bitmap
438        printf("saving preset bitmap to %s...\n", _result_filename);
439        preset->save(result_file);
440        delete result_file;
441    }
442    delete preset;
443    delete __PATHSET;
444    delete __PAIR2PATH;
445}
446
447//  ====================================================
448//  ====================================================
449
450int main(int argc,   char *argv[]) {
451
452   // open probe-set-database
453    if (argc < 2) {
454        printf("Missing argument\n Usage %s <database name> [[-]bitmap filename] [+result filename]\n ", argv[0]);
455        printf("if bitmap filename begins with '-' it is loaded, else its created\n ");
456        printf("result filename MUST be preceded by '+'\n");
457        exit(1);
458    }
459
460    const char *input_DB_name   = argv[1];
461    const char *bitmap_filename = NULp;
462    const char *result_filename = NULp;
463
464    if (argc > 2) {
465        if (argv[2][0] == '+') {
466            result_filename = argv[2]+1;
467        }
468        else {
469            bitmap_filename = argv[2];
470        }
471    }
472    if (argc > 3) {
473        if (argv[3][0] == '+') {
474            result_filename = argv[3]+1;
475        }
476        else {
477            bitmap_filename = argv[3];
478        }
479    }
480
481    struct tms before;
482    times(&before);
483    printf("Opening probe-set-database '%s'..\n", input_DB_name);
484    PS_Database *db = new PS_Database(input_DB_name, PS_Database::READONLY);
485    db->load();
486    __MAX_ID = db->getMaxID();
487    __MIN_ID = db->getMinID();
488    PS_print_time_diff(&before, "(enter to continue)  ");
489
490    __MAP = new PS_BitMap_Fast(false, __MAX_ID+1);
491    if (!bitmap_filename || (bitmap_filename[0] != '-')) {
492        printf("detecting..\n"); fflush(stdout);
493        __NODES_LEFT = (char*)malloc(61);
494        memset(__NODES_LEFT, ' ', 60);
495        __NODES_LEFT[60] = '\x00';
496        PS_detect_weak_differences(db->getRootNode());
497        free(__NODES_LEFT);
498        if (bitmap_filename) {
499            printf("saving bitmap to file %s\n", bitmap_filename);
500            PS_FileBuffer *mapfile = new PS_FileBuffer(bitmap_filename, PS_FileBuffer::WRITEONLY);
501            __MAP->save(mapfile);
502            delete mapfile;
503        }
504    }
505    else if (bitmap_filename) {
506        printf("loading bitmap from file %s\n", bitmap_filename+1);
507        PS_FileBuffer *mapfile = new PS_FileBuffer(bitmap_filename+1, PS_FileBuffer::READONLY);
508        __MAP->load(mapfile);
509        delete mapfile;
510    }
511    printf("(enter to continue)\n");
512
513    times(&before);
514    PS_print_and_evaluate_map(db->getRootNode(), result_filename);
515    PS_print_time_diff(&before, "(enter to continue)  ");
516    delete __MAP;
517
518    printf("removing database from memory\n");
519    delete db;
520    printf("(enter to continue)\n");
521
522    return 0;
523}
Note: See TracBrowser for help on using the repository browser.