ARB
ps_detect_weak_differences.cxx
Go to the documentation of this file.
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
22 static PS_BitMap_Fast *__MAP;
23 // globals for PS_detect_weak_differences
24 static IDVector *__PATH;
26 static unsigned long int __COUNT_SET_OPS = 0;
27 static unsigned long int __COUNT_SET_OPS2 = 0;
28 static char *__NODES_LEFT;
29 // globals for PS_print_and_evaluate_map
30 static IDSet *__PATHSET;
34 
35 #if defined(DEBUG)
36 void 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 
46 void 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 
57 static 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;
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;
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 
193 static 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 
227 typedef map<ID2IDPair, PS_NodePtr> IDID2NodeMap;
228 typedef IDID2NodeMap::iterator IDID2NodeMapIter;
229 typedef IDID2NodeMap::const_iterator IDID2NodeMapCIter;
230 
231 void 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 
289 static 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;
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 
450 int 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 }
static const bool READONLY
std::map< ID2IDPair, IDSet > IDID2IDSetMap
Definition: ps_defs.hxx:61
IDVector::const_iterator IDVectorCIter
Definition: ps_defs.hxx:34
const char * id
Definition: AliAdmin.cxx:17
PS_NodeMapIterator getChildrenBegin()
Definition: ps_node.hxx:114
IDID2IDSetMap::const_iterator IDID2IDSetMapCIter
Definition: ps_defs.hxx:63
void PS_print_time_diff(const struct tms *_since, const char *_before, const char *_after)
Definition: ps_tools.cxx:21
static SpeciesID __MIN_ID
std::set< SpeciesID > IDSet
Definition: ps_defs.hxx:39
SpeciesID getNum() const
Definition: ps_node.hxx:72
static void PS_detect_weak_differences(const PS_NodePtr &_root_node)
void put_long(long int _l)
IDID2NodeMap::const_iterator IDID2NodeMapCIter
void put_int(int _i)
size_t countChildren() const
Definition: ps_node.hxx:111
static void PS_detect_weak_differences_stepdown(const PS_NodePtr &_ps_node, const SpeciesID _parent_ID, const long _depth)
static IDVector * __INVERSE_PATH
static IDVector * __PATH
static unsigned long int __COUNT_SET_OPS
PS_NodeMap::const_iterator PS_NodeMapConstIterator
Definition: ps_node.hxx:58
static SpeciesID __MAX_ID
static SpeciesID __ONEMATCH_MAX_ID
fflush(stdout)
PS_NodeMapIterator getChildrenEnd()
Definition: ps_node.hxx:118
static SpeciesID __ONEMATCH_MIN_ID
static PS_BitMap_Fast * __MAP
void printOnlyMe() const
Definition: ps_node.hxx:214
IDID2NodeMap::iterator IDID2NodeMapIter
bool hasInverseProbes() const
Definition: ps_node.hxx:168
GB_write_int const char GB_write_autoconv_string WRITE_SKELETON(write_pointer, GBDATA *,"%p", GB_write_pointer) char *AW_awa if)(!gb_var) return strdup("")
Definition: AW_awar.cxx:166
std::set< ID2IDPair > ID2IDSet
Definition: ps_defs.hxx:54
ID2IDSet::const_iterator ID2IDSetCIter
Definition: ps_defs.hxx:56
static IDSet * __PATHSET
map< ID2IDPair, PS_NodePtr > IDID2NodeMap
static char * __NODES_LEFT
int main(int argc, char *argv[])
void PS_find_probes_for_pairs(const PS_NodePtr &_ps_node, ID2IDSet &_pairs)
static unsigned long int __COUNT_SET_OPS2
std::vector< SpeciesID > IDVector
Definition: ps_defs.hxx:32
#define NULp
Definition: cxxforward.h:97
pair< bool, PS_NodePtr > getChild(SpeciesID id)
Definition: ps_node.hxx:101
bool hasProbes() const
Definition: ps_node.hxx:159
bool hasPositiveProbes() const
Definition: ps_node.hxx:160
static void PS_print_and_evaluate_map(const PS_NodePtr &_root_node, const char *_result_filename)
std::pair< SpeciesID, SpeciesID > ID2IDPair
Definition: ps_defs.hxx:53
static const bool WRITEONLY
static IDID2IDSetMap * __PAIR2PATH
IDSet::const_iterator IDSetCIter
Definition: ps_defs.hxx:41